2010-05-27 15 views
51

E 'possibile aggiungere qualche valore da file di risorse direttamente nel markup XAML? O per la localizzazione dobbiamo sempre fare qualcosa di simile nel file * .cs:ottenere i valori da file * resx in XAML

txtMessage.Text = Messages.WarningUserMessage; 

Dove Messages è risorsa, e txtMessage è TextBlock.

+1

Come è stato creato il file di risorse Messaggi? Hai appena aggiunto Messages.resx alla tua cartella delle proprietà? Se è così, non posso raggiungere questo file. – Sergey

+0

@Sergey, non importa dove sia. Certo, puoi aggiungerlo anche alla cartella delle proprietà. Certo il file resx deve essere nella directory del progetto. Potrebbe non essere possibile aggiungerlo alla directory delle proprietà di VS? Btw è una cattiva pratica per aggiungere smth alla directory delle proprietà. Creare una directory "risorsa" migliore per conservare i file res. – 0x49D1

risposta

59

Assicurarsi che il codice Generation è impostato su pubblico nell'editor resx, allora si può semplicemente utilizzare:

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

Sono nuovo di WPF e questa risposta è proprio quello di cui avevo bisogno! Grazie. – 0x49D1

+0

Si noti che funziona solo se 'Messaggi' si trova nello stesso spazio dei nomi dello schermo. –

+3

... e se 'Messages' non è in un altro assembly poiché il costruttore è generato come interno. –

5

Il modo più semplice è probabilmente quello di riferimento le voci direttamente (sono proprietà statiche, interni di default):

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

Se si sta lavorando su un localizzata WPF applicazione anche se allora vi consiglierei di dare un'occhiata alla guida su CodePlex a http://wpflocalization.codeplex.com/, e se si sta costruendo un'applicazione composita (con prisma o MEF) allora ho un blog post on a nice way to accomplish WPF localisation using standard bindings.

53

E 'molto più facile da fare in questo modo. Aggiungi un xmlns nel file XAML e utilizza direttamente le risorse.

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

L'unico svantaggio di questo approccio è che ovviamente non puoi cambiare la cultura in modo dinamico. C'è un ottimo articolo su come realizzare quel comportamento attraverso l'uso di un'estensione di markup e di un localization manager da qualche parte. –

+4

qui è: http://www.grumpydev.com/2009/09/08/localising-wpf-applications-using-resx-files-and-standard-data-binding-without-a-markupextension/ –

1

Dopo un'indagine giorno intero questo commento Xaml localization: Using .resx Resources in Xaml without x:static ho trovato una soluzione semplice per fornire supporto multilingua con (risorse incorporate o assembly di riferimento) * resx - file. Dal Framework 4 esiste una classe base chiamata DynamicObject per specificare il comportamento dinamico in fase di esecuzione nello spazio dei nomi System.Dynamic.

I derivati ​​seguente ResourceLoader da System.Dynamic.DynamicObject - classe:

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 
} 

È possibile creare un'istanza all'interno di XAML come questo:

<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> 

codice C#:

/// <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;      
    }  
} 

Ora è possibile associare stringhe e immagini (le immagini saranno convertiti in 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

ho capito la mia risposta è un po 'tardi, ma ho pensato che la sua vale la pena condividere:

Per all'utente una stringa memorizzata nel file * .resx senza Statico parola chiave:

  1. nel file di App.xaml aggiungere uno spazio dei nomi per le proprietà xmlns:resource="clr-namespace:YourProject.Properties"
  2. In ApplicationResources (file app.xaml) Aggiungi una risorsa per *.resx

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

  3. Nel file XAML utilizzare il seguente Binding, consente di dare un esempio di titolo della finestra

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

    titlestring è il nome del StringProperty nel file * .resx

  4. Ultimo ma non meno importante, non dimenticare di modificare il modificatore di accesso al file di risorse su Pubblico.

Enjoy :)

+0

Come è stato lo fai funzionare? Ho seguito esattamente le tue istruzioni, ma il file di risorse (con un modificatore di accesso pubblico impostato su "Pubblico") creato fondamentalmente contiene una classe statica con un costruttore protetto. Sia in WPF che in Metro, ricevo un errore "il tipo ResourceFileName non include costruttori accessibili" nella finestra di progettazione XAML (e un altro errore simile quando compila). –

+0

Esattamente, stesso errore come elencato sopra. – Hekkaryk

-1

nascondere un altro blocco di testo e associarlo è il testo In questo blocco di testo avrete la risorsa da cs

0

Il modo più semplice, in cui è possibile definire la larghezza di casella di testo anche in base alla lunghezza del testo in ciascuna lingua.

Xaml Codice

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

risorse file: -

Nome - Valore

Greeting.Text - Ciao

Greeting.width - 20

Have a look at resource file:- Click View

+0

Si prega di formattare il codice come tale, inserire 4 spazi di fronte per tutte le righe di codice. – Luuklag