2010-05-27 13 views
51

Czy jest możliwe dodanie wartości z pliku zasobów bezpośrednio do znaczników XAML? Lub do lokalizacji zawsze musimy zrobić coś takiego w pliku * .cs:Uzyskaj wartości z plików * .resx w XAML

txtMessage.Text = Messages.WarningUserMessage; 

Gdzie Messages jest zasobem, a txtMessage jest TextBlock.

+1

W jaki sposób utworzyłeś plik zasobów Messages? Czy właśnie dodałeś Messages.resx do folderu właściwości? Jeśli tak, nie mogę osiągnąć tego pliku. – Sergey

+0

@Sergey, bez względu na to gdzie jest. Oczywiście, możesz dodać go również do folderu właściwości. Plik Sure resx musi znajdować się w katalogu projektu. Może nie możesz dodać go do katalogu właściwości z VS? Btw to jest zła praktyka, aby dodać coś do katalogu właściwości. Lepiej stwórz katalog "zasobów" do przechowywania plików res. – 0x49D1

Odpowiedz

59

Upewnij się, że kod Generation jest ustawiony na publiczny w RESX edytorze, a następnie można po prostu użyć:

<TextBlock Text="{x:Static Messages.WarningUserMessage}" /> 
+1

Jestem nowy w WPF i ta odpowiedź jest właśnie tym, czego potrzebowałem! Dziękuję Ci. – 0x49D1

+0

Zauważ, że działa tylko wtedy, gdy 'Wiadomości' jest w tym samym obszarze nazw co ekran. –

+3

... a jeśli "Komunikaty" nie znajdują się w innym zestawie, ponieważ konstruktor jest generowany jako wewnętrzny. –

5

Najprostszym sposobem jest prawdopodobnie bezpośrednio odwoływać się do elementów (są właściwości statyczne, wewnętrzne domyślnie):

<TextBlock x:Name="txtMessage" Text="{x:Static MyApp.Properties.Resource.TextString}"/> 

Jeśli pracujesz w zlokalizowanej aplikacji WPF chociaż wtedy polecam przyjrzeniu kierunkiem na CodePlex na http://wpflocalization.codeplex.com/, a jeśli budujemy aplikację kompozytową (przy użyciu pryzmat lub MEF) następnie mam blog post on a nice way to accomplish WPF localisation using standard bindings.

53

Dużo łatwiej jest to zrobić w ten sposób. Dodaj xmlns do pliku XAML i korzystaj z zasobów bezpośrednio.

xmlns:resx="clr-namespace:wpfapplicationname.Properties" 
Title="{x:Static resx:Resources.name}" 
+2

Jedyną wadą tego podejścia jest oczywiście to, że nie możesz dynamicznie zmieniać kultury. Istnieje świetny artykuł o tym, jak osiągnąć to zachowanie, używając rozszerzenia do oznaczania i gdzieś gdzieś znajduje się menedżer lokalizacji. –

+4

o to tutaj: http://www.grumpydev.com/2009/09/08/localising-wpf-aplikacje-korzystanie-resx-files-and-standard-data-binding-without-a-markupextension/ –

1

Po całym dochodzeniu dzień ten komentarz Xaml localization: Using .resx Resources in Xaml without x:static znalazłem proste rozwiązanie, aby zapewnić obsługę wielu języków (z wbudowanych zasobów lub odwołuje montaż) * .resx - pliki. Od Framework 4 istnieje klasa bazowa o nazwie DynamicObject do określania dynamicznego zachowania w czasie wykonywania w przestrzeni nazw System.Dynamic.

I pochodzą z następujących ResourceLoader System.Dynamic.DynamicObject - klasa:

public class ResourceLoader : DynamicObject 
{ 
    #region Fields --------------------------------------------------------------- 

    private const string DefaultResourcesSuffix = "Resource"; 
    private ResourceManager _resourceMan; 
    private CultureInfo culture; 
    private readonly string _defaultAssemblyName; 
    private readonly Assembly _defaultAssembly; 
    private Assembly theAssembly; 
    private string resourcesSuffix; 
    private string assembly; 

    #endregion // Fields 

    #region Properties ----------------------------------------------------------- 

    /// <summary> 
    /// Gets or sets the assembly. 
    /// </summary> 
    public string Assembly 
    { 
     get { return assembly; } 
     set 
     { 
      assembly = value; 
      theAssembly = System.Reflection.Assembly.Load(assembly); 
      _resourceMan = null; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the resources suffix. 
    /// </summary> 
    public string ResourcesSuffix 
    { 
     get { return resourcesSuffix; } 
     set 
     { 
      resourcesSuffix = value; 
      _resourceMan = null; 
     } 
    } 

    /// <summary> 
    /// Get, set culture 
    /// </summary> 
    public CultureInfo CurrentCulture 
    { 
     get { this.culture = this.culture ?? CultureInfo.InvariantCulture; return this.culture; } 
     set { this.culture = value; } 
    } 

    /// <summary> 
    /// Creates new instace of <see cref="System.Resources.ResourceManager"/> at initialisation or change of <see cref="ResourceFileAccessSample.ResourceBinding.ResourceLoader.Assembly"/>. 
    /// </summary> 
    private ResourceManager ResourceManager 
    { 
     get 
     { 
      if (ReferenceEquals(_resourceMan, null)) 
      { 
       ResourceManager temp = new ResourceManager(
        string.Format("{0}.{1}", Assembly ?? _defaultAssemblyName, ResourcesSuffix ?? DefaultResourcesSuffix), 
        theAssembly ?? _defaultAssembly); 
       _resourceMan = temp; 
      } 
      return _resourceMan; 
     } 
    } 

    #endregion // Properties 

    #region Methods -------------------------------------------------------------- 

    private object GetResource(string name, CultureInfo language) 
    { 
     if (language == null || language == CultureInfo.InvariantCulture) 
      return ResourceManager.GetObject(name); 
     return ResourceManager.GetObject(name, language); 
    } 

    /// <summary> 
    /// Provides the implementation for operations that get member values. Classes derived from the <see cref="T:System.Dynamic.DynamicObject"/> class can override this method to specify dynamic behavior for operations such as getting a value for a property. 
    /// </summary> 
    /// <param name="binder">Provides information about the object that called the dynamic operation. The binder.Name property provides the name of the member on which the dynamic operation is performed. For example, for the Console.WriteLine(sampleObject.SampleProperty) statement, where sampleObject is an instance of the class derived from the <see cref="T:System.Dynamic.DynamicObject"/> class, binder.Name returns "SampleProperty". The binder.IgnoreCase property specifies whether the member name is case-sensitive.</param> 
    /// <param name="result">The result of the get operation. For example, if the method is called for a property, you can assign the property value to <paramref name="result"/>.</param> 
    /// <returns> 
    /// true if the operation is successful; otherwise, false. If this method returns false, the run-time binder of the language determines the behavior. (In most cases, a run-time exception is thrown.) 
    /// </returns> 
    public override bool TryGetMember(GetMemberBinder binder, out object result) 
    { 
     result = GetResource(binder.Name, this.culture); 

     if (result != null && result.GetType() == typeof(System.Drawing.Bitmap)) 
     { 
      System.Drawing.Bitmap currentBmp = result as System.Drawing.Bitmap; 
      currentBmp.MakeTransparent(System.Drawing.Color.Magenta); 
      BitmapSource src = Imaging.CreateBitmapSourceFromHBitmap(currentBmp.GetHbitmap(), IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions()); 
      result = src; 
     } 
     return result == null ? false : true; 
    } 

    /// <summary> 
    /// Switch set culture 
    /// </summary> 
    public void SwitchCulture(CultureInfo NewCulture) 
    { 
     this.culture = NewCulture; 
    } 
    #endregion // Methods 

    #region Constructors --------------------------------------------------------- 

    /// <summary> 
    /// Initializes a new instance of the <see cref="ResourceLoader"/> class. 
    /// </summary> 
    public ResourceLoader() 
     : this(CultureInfo.InvariantCulture, DefaultResourcesSuffix) 
    { } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="ResourceLoader"/> class. 
    /// </summary> 
    public ResourceLoader(CultureInfo InitCulture, string ResourceSuffix) 
    { 
     _defaultAssemblyName = GetType().Assembly.GetName().Name; 
     _defaultAssembly = GetType().Assembly; 
     this.culture = InitCulture; 
     this.resourcesSuffix = ResourceSuffix; 
    } 

    #endregion // Constructors 
} 

Można utworzyć instancję ciągu XAML tak:

<Application x:Class="ResourceFileAccessSample.App" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"   
     xmlns:src="clr-namespace:ResourceFileAccessSample.ResourceBinding"    
     StartupUri="Window1.xaml" Startup="Application_Startup" > 

<Application.Resources> 
    <src:ResourceLoader x:Key="resource" CurrentCulture="(Default)" ResourcesSuffix="Resource" /> 
</Application.Resources> 

C# Kod:

/// <summary> 
/// Interaction logic for Window1.xaml 
/// </summary> 
public partial class Window1 : Window 
{ 
    private ResourceLoader res; 
    public Window1() 
    {    
     InitializeComponent(); 
     // load it from WPF Resources 
     this.res = (ResourceLoader)this.FindResource("resource"); 
     // or create an instance 
     //this.res = new ResourceLoader(CultureInfo.InvariantCulture, "Resource");  
     this.LayoutRoot.DataContext = res;      
    } 

    private void btnSwichLanguage_Click(object sender, RoutedEventArgs e) 
    {    
     res.SwitchCulture(new CultureInfo("de"));    
     this.LayoutRoot.DataContext = null; 
     this.LayoutRoot.DataContext = res;      
    }  
} 

Teraz jest to możliwe, aby związać łańcuchy i obrazów (obrazy zostaną przekształcone w WPF compilant BitmapSource:

<StackPanel Name="LayoutRoot" Orientation="Vertical"> 
    <Label Name="lblText" Content="{Binding Path=rsName, Mode=OneWay}" HorizontalContentAlignment="Center" Margin="5" Padding="0" /> 
    <Image Source="{Binding Path=AlignObjectsTop}" Height="16" Width="16" Margin="5" /> 
    <Button Name="btnSwichLanguage" Content="Switch to de" Click="btnSwichLanguage_Click" MinHeight="25" Width="100" /> 

</StackPanel> 
8

Rozumiem moją odpowiedź jest nieco późno, ale myślałem, że jego udostępnianie Wartość:

Aby użytkownikowi ciąg przechowywane w pliku * .resx bez słowa kluczowego static:

  1. w pliku App.xaml dodać nazw dla Properties xmlns:resource="clr-namespace:YourProject.Properties"
  2. W ApplicationResources (plik app.xaml) Dodaj zasób dla swojego *.plik RESX

    <Application.Resources> <resource:ResourceFileName x:Key="ApplicationStringResources" /> </Application.Resources>

  3. W pliku XAML wykorzystać następujące wiążące, weźmy przykład Window Title

    Title="{Binding TitleString, Source={StaticResource ResourceKey=ApplicationStringResources}}"

    TitleString to nazwa StringProperty w * .resx pliku

  4. Ostatni, ale nie najmniej ważny, nie zapomnij zmienić modyfikatora dostępu do pliku zasobów na Publiczny.

Enjoy :)

+0

Jak to się stało czy to działa? Dokładnie przestrzegałem twoich instrukcji, ale plik zasobów (z modyfikatorem publicznego dostępu ustawionym na "Publiczny") zasadniczo zawiera klasę statyczną z chronionym konstruktorem. W obu WPF i Metro pojawia się błąd "typ ResourceFileName nie zawiera żadnych dostępnych konstruktorów" w projektancie XAML (i inny, podobny błąd podczas kompilacji). –

+0

Dokładnie, ten sam błąd, jak podano powyżej. – Hekkaryk

-1

Ukryj inny textblock i wiążą to tekst W tym textblock musisz zasób z .cs

0

Najprostszym sposobem, w którym można określić szerokość pole tekstowe również zgodnie z długością tekstu w każdym języku.

kod Xaml

<TextBlock x:Uid="Greeting" Text="" /> 

zasobów pliku: -

Name - Wartość

Greeting.Text - Witam

Greeting.width - 20

Have a look at resource file:- Click View

+0

Proszę sformatować swój kod jako taki, wprowadź 4 spacje przed nim dla wszystkich wierszy kodu. – Luuklag

Powiązane problemy