Получить значения из файлов * .resx в XAML - PullRequest
66 голосов
/ 27 мая 2010

Можно ли добавить какое-либо значение из файла ресурсов прямо в разметку XAML? Или для локализации мы всегда должны сделать что-то подобное в файле * .cs:

txtMessage.Text = Messages.WarningUserMessage;

Где Messages - ресурс, а txtMessage - TextBlock.

Ответы [ 7 ]

73 голосов
/ 27 мая 2010

Убедитесь, что в редакторе resx для Code Generation установлено значение Public, тогда вы можете просто использовать:

<TextBlock Text="{x:Static Messages.WarningUserMessage}" />
58 голосов
/ 16 сентября 2011

Гораздо проще сделать это так. Добавьте xmlns в файл XAML и используйте ресурсы напрямую.

xmlns:resx="clr-namespace:wpfapplicationname.Properties"
Title="{x:Static resx:Resources.name}"
10 голосов
/ 10 марта 2015

Я понимаю, что мой ответ немного запоздал, но я подумал, что стоит поделиться:

Чтобы использовать строку, хранящуюся в файле * .resx без ключевого слова Static:

  1. В файле App.Xaml добавьте пространство имен для свойств xmlns:resource="clr-namespace:YourProject.Properties"
  2. В ApplicationResources (файл app.xaml) добавьте ресурс для вашего * .resx файла

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

  3. В вашем файле XAML используйте следующую привязку, давайте рассмотрим пример заголовка окна

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

    TitleString - это имя StringProperty в вашем * .resx файле

  4. И последнее, но не менее важное: не забудьте изменить модификатор доступа к файлу ресурса на Public.

5 голосов
/ 27 мая 2010

Самый простой способ, вероятно, состоит в том, чтобы ссылаться на элементы напрямую (они являются статическими свойствами, по умолчанию внутренними):

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

Если вы работаете над локализованным приложением WPF, я бы порекомендовал взглянуть на руководство по CodePlex на http://wpflocalization.codeplex.com/, а если вы создаете составное приложение (с использованием PRISM или MEF), тогда У меня есть сообщение в блоге о хорошем способе локализации WPF с использованием стандартных привязок .

1 голос
/ 23 января 2015

После целого дня изучения этого комментария Локализация Xaml: Использование ресурсов .resx в Xaml без x: static Я нашел простое решение для обеспечения поддержки мультиязычности с помощью (встроенных ресурсов или ссылочной сборки) * .resx - файлы. Начиная с Framework 4, существует базовый класс DynamicObject для определения динамического поведения во время выполнения в пространстве имен System.Dynamic.

Я получил следующий ResourceLoader из System.Dynamic.DynamicObject - класс:

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
}

Вы можете создать экземпляр в xaml следующим образом:

<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 # код:

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

Теперь возможно связывать строки и изображения (изображения будут преобразованы в WPF-совместимый 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>
0 голосов
/ 22 августа 2017

Самый простой способ, где вы можете определить ширину текстового поля также в соответствии с длиной текста на каждом языке.

Код Xaml

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

Посмотрите на файл ресурса: - Нажмите Просмотр

0 голосов
/ 22 сентября 2015

Скрыть другой текстовый блок и связать его текст В этом текстовом блоке у вас будет ресурс из .cs

...