22

是否可以使用价值转换器而不必事先将它们定义为资源?

现在我有

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

谢谢

4

4 回答 4

27

在单例类型IValueConverter的情况下(例如,它们不需要来自当前绑定实例的任何状态)我使用静态转换器,即:

Converter={x:Static SomeNamespace:SomeConverter.Instance}

WPF 博士也有一篇很棒的文章,关于使用标记扩展使其内联更清晰。

于 2010-02-21T00:32:50.140 回答
7

从技术上讲,我相信你可以做到这一点,但 XAML 太可怕了,相比之下,它会使“大量琐碎的资源”方法看起来像一个简单明了的避风港:

<Button Height="50">
  <Button.Width>
    <Binding Path="Width" ElementName="textBox1" UpdateSourceTrigger="PropertyChanged">
      <Binding.Converter>
        <local:TrivialFormatter />
      </Binding.Converter>
    </Binding>
  </Button.Width>
</Button>

我没有测试过这个,因为即使阅读它也会让我的眼睛流泪......

于 2010-02-21T00:33:45.743 回答
6

我肯定会研究 Micah 的建议,其中涉及使用转换器的静态单例实例。但要考虑的另一件事是,如果您使用像 MVVM 这样的分离表示模式,您通常可以通过在 ViewModel 中实现转换来避免对值转换器的要求。

您可能想要这样做的原因有很多。

一方面,它更具可测试性。您的单元测试可以确保从 ViewModel 出来的东西就是 UI 将显示的东西。您可以想象测试美元值必须遵循当前文化的货币格式、必须使用两位小数等要求。

另一个很好的理由是值转换器中的异常不会被视为验证错误,这在 Silverlight 中可能是一个巨大的痛苦。即使您在绑定中将 ValidatesOnExceptions 设置为 true,如果您的值转换器引发异常,Silverlight 也会让它传播。但是,如果您使用 ViewModel 进行转换,则会将异常视为验证错误。

缺点是您失去了通用值转换器的一些“可重用性”。

于 2010-02-21T01:03:25.067 回答
1

我不知道有一种方法可以按照您所说的方式执行此操作,但我只是将其作为示例进行了尝试,并且有效。在您的 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 解析器不知道何时以及要创建多少个转换器实例。将其创建为资源确保只有一个实例。

于 2010-02-21T00:22:06.740 回答