开发环境
VS2022
.net 8.0
问题背景
在做软件本地化,将UI绑定相应的资源文件中的相应名称后,出现下述错误:
即:无法将“WpfApp1.Properties.Resources.TextBlock1_TextBlock_Text”StaticExtension 值解析为枚举、静态字段或静态属性。
问题UI代码如下:
<Window
x:Class="WpfApp1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:control="clr-namespace:WpfApp1.Control"
xmlns:converter="clr-namespace:WpfApp1.Converter"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:loc="clr-namespace:WpfApp1.Properties"
xmlns:local="clr-namespace:WpfApp1"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewmodels="clr-namespace:WpfApp1.VM"
x:Uid="Window1Title"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.DataContext>
<viewmodels:MainWindowViewModel />
</Window.DataContext>
<Grid>
<StackPanel>
<Button Command="{Binding StopTimerCommand}" Content="{x:Static loc:Resources.TextBlock1_TextBlock_Text}" />
</StackPanel>
</Grid>
</Window>
涉及到的资源文件如下:
在.net framework4.8.2下,上述代码是能够正常运行的,移到.net 8.0就不能正常工作了。
原因探索及验证
一通搜索,查找到一个说将资源的访问修饰符修改为public,即可解决问题。也就是说,资源文件的访问修饰符必须设置为public,才能xaml界面进行正确的绑定。
以下是为什么需要将资源设置为 public
的几个原因:
-
XAML 编译需求: WPF XAML 编译器需要能够识别和访问资源文件中定义的资源。如果资源不是
public
,编译器无法在编译时将它们编译到程序集中。 -
静态成员访问:
x:Static
扩展用于引用 CLR(Common Language Runtime)中的静态成员。如果资源不是public
,它们就不会被视为静态成员,因此无法通过x:Static
扩展进行访问。 -
程序集元数据: 当资源文件中的资源被标记为
public
时,它们会被嵌入到程序集的元数据中。这样,XAML 解析器就可以在程序集加载时找到并访问这些资源。 -
设计时和运行时访问: 在 Visual Studio 设计视图中预览 XAML 时,以及在应用程序运行时,都需要能够访问这些资源。如果资源不是
public
,设计视图可能无法正确显示资源,运行时也可能无法找到资源。
明白了原因,也有了一个可能解决办法;但是新的问题来了,怎么修改资源文件的访问修饰符呢?以前只要双击资源文件,即可打开资源文件,并且在资源文件的右上角,就能看到访问修饰符,然后进行相应的选择,即可进行修改。然当前进行双击操作后如下:
这要上哪儿去找资源的访问修饰符呢?
使用搜索,然无济于事;求助AI,却是胡说八道;求助,无人应答;求己,无从下手……再次陷入迷茫。
然天无绝人之路,一通瞎操作,发现可以找到了VS中原来的资源管理工具,然后调用它打开就能修改访问修饰符。且经验证,修改访问修饰符确实有效,能解决此问题。
VS2022修改访问修饰符操作步骤
- 右键资源文件,然后选择 打开方式 如下图所示:
- 点击上图中的 打开方式 ,然后会弹出下述菜单:
- 选择上图中的 受管理资源编辑器(旧版) 点击确定(当然你也可以直接选择上图中的 设为默认值 );点击确定后如下图:
- 在上图中,即可找到访问修饰符,进行相应的修改即可。
修改资源文件代码中的访问修饰符
除了上述办法外,还有一个简单粗暴的方法,就是直接修改资源文件的代码文件中的访问修改符。
打开下图红框中代码文件:
上图中代码文件如下:
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本:4.0.30319.42000
//
// 对此文件的更改可能会导致不正确的行为,并且如果
// 重新生成代码,这些更改将会丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace WpfApp1.Properties {
using System;
/// <summary>
/// 一个强类型的资源类,用于查找本地化的字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources {
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources() {
}
/// <summary>
/// 返回此类使用的缓存的 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager {
get {
if (object.ReferenceEquals(resourceMan, null)) {
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WpfApp1.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture {
get {
return resourceCulture;
}
set {
resourceCulture = value;
}
}
/// <summary>
/// 查找类似 测试 的本地化字符串。
/// </summary>
internal static string TextBlock1_TextBlock_Text {
get {
return ResourceManager.GetString("TextBlock1_TextBlock.Text", resourceCulture);
}
}
/// <summary>
/// 查找类似 窗口标题 的本地化字符串。
/// </summary>
internal static string Window1Title_Window_Title {
get {
return ResourceManager.GetString("Window1Title_Window.Title", resourceCulture);
}
}
}
}
将上述代码中类和属性的访问修饰符从internal修改为public即可。
参考链接
WPF中添加资源报错“无法StaticExtension 值解析为枚举、静态字段或静态属性”的解决方法 - Dwaynerbing - 博客园 (cnblogs.com)