多语言应用中FallbackValue设DynamicResource报错的解决方案咨询
这个问题我之前做WPF多语言本地化项目时也踩过完全一样的坑!先给你拆解一下为什么会报这个错:
You can set 'DynamicResourceExtension' for the 'StringFormat' type 'Binding' property. You can set 'DynamicResourceExtension' only for a DependencyProperty of a DependencyObject
简单来说,DynamicResourceExtension是WPF依赖属性系统的特性,它只能赋值给DependencyObject的DependencyProperty——比如TextBlock.Text就是典型的依赖属性。但Binding.FallbackValue和Binding.StringFormat都是Binding类的普通CLR属性,Binding本身并不是DependencyObject,所以直接给这些属性塞DynamicResource就会触发异常。
下面根据你的需求场景,给你两种针对性的解决方案:
场景1:需要让FallbackValue使用动态更新的多语言字符串
如果你是想让绑定失败时显示的回退文本是动态的(比如切换语言时自动更新),可以用PriorityBinding替代FallbackValue:
<TextBlock> <TextBlock.Text> <PriorityBinding> <!-- 第一个绑定:你的目标数据源 --> <Binding Path="YourDataProperty" /> <!-- 第二个绑定:动态资源作为回退值,因为绑定的是TextBlock.Text(依赖属性),所以DynamicResource有效 --> <Binding Source="{DynamicResource FallbackLocalizedText}" /> </PriorityBinding> </TextBlock.Text> </TextBlock>
原理是PriorityBinding会按顺序尝试绑定,第一个绑定失败(比如值为null、数据源不存在)时,就会自动使用第二个绑定的结果,而且因为第二个绑定是直接作用于Text这个依赖属性,所以DynamicResource可以正常工作,语言切换时也会自动更新文本。
场景2:需要让StringFormat使用动态更新的多语言格式字符串
如果报错是因为你给Binding.StringFormat赋值了DynamicResource,可以用附加属性来实现动态更新的格式字符串:
首先在代码里定义一个附加属性:
using System.Windows; using System.Windows.Data; public static class DynamicFormatHelper { public static string GetStringFormat(DependencyObject obj) { return (string)obj.GetValue(StringFormatProperty); } public static void SetStringFormat(DependencyObject obj, string value) { obj.SetValue(StringFormatProperty, value); } public static readonly DependencyProperty StringFormatProperty = DependencyProperty.RegisterAttached( "StringFormat", typeof(string), typeof(DynamicFormatHelper), new PropertyMetadata(null, OnStringFormatChanged)); private static void OnStringFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (d is FrameworkElement element) { // 获取当前的Text绑定 var binding = BindingOperations.GetBinding(element, TextBlock.TextProperty); if (binding != null) { // 更新绑定的StringFormat并重新绑定 binding.StringFormat = e.NewValue as string; BindingOperations.SetBinding(element, TextBlock.TextProperty, binding); } } } }
然后在XAML中使用:
<TextBlock Text="{Binding YourNumberProperty}" local:DynamicFormatHelper.StringFormat="{DynamicResource NumberFormatString}" />
当你的NumberFormatString动态资源更新(比如切换语言时),附加属性会自动触发绑定更新,从而实现动态的格式字符串效果,完全避开了直接给Binding.StringFormat赋值DynamicResource的限制。
最后再划个重点
记住一个核心规则:DynamicResource只能用在依赖对象的依赖属性上,所有非依赖属性(比如Binding的各种配置属性)都不能直接用它赋值,必须通过依赖属性相关的技巧绕过去~
内容的提问来源于stack exchange,提问作者oÆÞ

