从XAML中的* .resx文件获取值


74

是否可以将资源文件中的某些值直接添加到XAML标记中?或为了进行本地化,我们总是必须在* .cs文件中进行如下操作:

txtMessage.Text = Messages.WarningUserMessage;

Messages资源txtMessage是哪里,文本块是哪里。


2
您是如何创建Messages资源文件的?您是否刚刚将Messages.resx添加到属性文件夹?如果是这样,我将无法访问此文件。
谢尔盖(Sergey)

@Sergey,无论身在何处。当然,您也可以将其添加到properties文件夹。确保resx文件必须位于项目目录中。可能无法将其从VS添加到属性目录吗?顺便说一句,这是将smth添加到properties目录的错误做法。更好地创建“资源”目录来保存您的res文件。
0x49D1 2011年

Answers:


85

确保在resx编辑器中将“代码生成”设置为“公共”,然后可以简单地使用:

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

1
我是WPF的新手,而这个答案正是我所需要的!谢谢。
0x49D1 2010年

2
请注意,它仅Messages在与屏幕相同的名称空间中起作用。
Julien N

4
...并且ifMessages不在不同的程序集中,因为构造函数是作为内部生成的。
Davi Fiamenghi

@DaviFiamenghi:构造函数没关系,我们在这里只访问静态成员。
Julien Lebosquain

2
您仍然需要像@Yogs回答xmlns:resource =“ clr-namespace:YourProject.Properties”一样在设计器中添加名称空间,并像{x:Static resource:Resources.ResourceName}一样使用它
Ilya Kochetov

71

这样做很容易。在XAML文件中添加xmlns并直接使用资源。

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

3
这种方法的唯一缺点当然是您不能动态更改文化。有一篇很棒的文章介绍了如何通过在某处使用标记扩展和本地化管理器来实现该行为。
斯蒂芬·德鲁


14

我知道我的回复有些晚,但是我认为值得分享:

要使用存储在* .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是* .resx文件中StringProperty的名称

  4. 最后但并非最不重要的一点是,不要忘记将资源文件访问修饰符更改为Public。


1
您是如何使它工作的?我完全按照您的指示进行操作,但是创建的资源文件(将公共访问修饰符设置为“公共”)基本上包含带有受保护构造函数的静态类。在WPF和Metro中,在XAML设计器中都出现错误“ ResourceFileName类型不包括任何可访问的构造函数”(以及另一个在编译时发生的类似错误)。
Quarkly

为我工作。只是努力寻找.resx的编译“ public”选项。打开.resx文件时,它是.resx编辑器顶部的一个很小的下拉菜单。另外,该项目需要重建,以使字符串可用
Marco

确保在最后重建解决方案
Trake Vital

对于我来说,要使其在VS 2019 v16.6.5中工作,必须将Resources.resx文件中的Properties> Build Action从“ Embedded Resource”更改为“ None”,然后再更改为“ Embedded Resource”。对我来说,这似乎是一个错误,但确实有效。
Brett Wertz

5

最简单的方法可能是直接引用项目(它们是静态属性,默认情况下是内部属性):

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

如果您正在使用本地化的WPF应用程序,那么我建议您参阅http://wpflocalization.codeplex.com/上有关CodePlex的指南,以及如果您正在构建复合应用程序(使用PRISM或MEF)然后我有一篇博客文章,介绍了一种使用标准绑定完成WPF本地化的好方法


1

经过一整天的调查,此评论Xaml本地化:在不带x:static的Xaml中使用.resx资源,我找到了一个简单的解决方案,以* .resx-文件(嵌入的资源或引用的程序集)提供多语言支持。从Framework 4开始,有一个名为DynamicObject的基类,用于在名称空间System.Dynamic中指定运行时的动态行为。

我从System.Dynamic.DynamicObject-类派生以下ResourceLoader:

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>

这与MVVM模式不兼容,因为ResourceLoader已分配给DataContext,而后者不再可与ViewModel一起使用。
Jinjinov


-2

隐藏另一个文本块并绑定其文本在该文本块中,您将获得.cs的资源

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.