是否可以使用值转换器而无需事先将它们定义为资源?
现在我有
<Window.Resources>
<local:TrivialFormatter x:Key="trivialFormatter" />
</Window.Resources>
和
<Button Width="{Binding Width,
ElementName=textBox1,
UpdateSourceTrigger=PropertyChanged,
Converter={StaticResource trivialFormatter}}">
不是必须在Window.Resources中声明trivialFormatter资源,我可以直接从Button的宽度绑定中引用它吗?像
这样的东西Converter = {local:TrivialFormatter}
由于
答案 0 :(得分:24)
对于单例类型IValueConverter
s(例如它们不需要当前绑定实例中的任何状态)我使用静态转换器,即:
Converter={x:Static SomeNamespace:SomeConverter.Instance}
WPF博士还发表了一篇很棒的文章,内容是使用标记扩展来使内联网更清晰here。
答案 1 :(得分:6)
从技术上讲,我相信你可以做到这一点,但XAML是如此可怕,相比之下它会让“许多琐碎资源”的方法看起来像一个简单明了的避风港:
<Button Height="50">
<Button.Width>
<Binding Path="Width" ElementName="textBox1" UpdateSourceTrigger="PropertyChanged">
<Binding.Converter>
<local:TrivialFormatter />
</Binding.Converter>
</Binding>
</Button.Width>
</Button>
我没有对此进行测试,因为即使阅读它也让我的眼睛流水......
答案 2 :(得分:5)
我肯定会查看Micah的建议,其中涉及使用转换器的静态单例实例。但另一件需要考虑的事情是,如果你使用像MVVM这样的独立表示模式,你通常可以通过在ViewModel中实现转换来避免对值转换器的要求。
您可能有很多理由要这样做。
首先,它更可测试。您的单元测试可以确保从ViewModel发出的内容是UI将显示的内容。您可以想象测试一个要求,即美元值必须遵循当前文化的货币格式,必须使用两位小数等。
另一个很好的理由是,值转换器中的异常将不视为验证错误,这可能是Silverlight中的一个巨大痛苦。即使您在绑定中将ValidatesOnExceptions设置为true,如果您的值转换器抛出异常,Silverlight也会让它传播。但是,如果您使用ViewModel进行转换,则会将异常视为验证错误。
缺点是你失去了通用值转换器的一些“可重用性”。
答案 3 :(得分:2)
我不知道如何以你说的方式做到这一点,但我只是尝试了这个作为样本并且它有效。在App.xaml.cs文件中,您可以创建一个使用反射来加载转换器的方法。
private void Application_Startup(object sender, StartupEventArgs e)
{
LoadConverters();
}
private void LoadConverters()
{
foreach(var t in Assembly.GetExecutingAssembly().GetTypes())
{
if (t.GetInterfaces().Any(i => i.Name == "IValueConverter"))
{
Resources.Add(t.Name, Activator.CreateInstance(t));
}
}
}
然后你就可以像这样使用转换器了,我估计有一半。
<Button Width="{Binding Width, Converter={StaticResource TrivialFormatter}}" />
您提出的方法的问题是Xaml解析器不知道您要创建转换器的时间和数量。将其创建为资源只能确保一个实例。