Using Value Converters in WPF without having to define them as resources first

只谈情不闲聊 提交于 2019-11-27 01:50:08

问题


Is it possible to use value converters without having to define them beforehand as resources?

Right now I have

<Window.Resources>
    <local:TrivialFormatter x:Key="trivialFormatter" />
</Window.Resources>

and

<Button Width="{Binding Width, 
               ElementName=textBox1, 
               UpdateSourceTrigger=PropertyChanged, 
               Converter={StaticResource trivialFormatter}}">

Wouldn't it be possible that instead of having to declare the trivialFormatter resource in Window.Resources, I could directly refer it from the Button's width binding? Something like

Converter = {local:TrivialFormatter}

Thanks


回答1:


In the case of singleton-type IValueConverters (e.g. they don't need any state from the current binding instance) I use static converters, i.e.:

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

There's also a great post by Dr. WPF on using a markup extension to make it cleaner inline here.




回答2:


Technically I believe you can do this, but the XAML is so horrible that it will make the "lots of trivial resources" approach look like a haven of simplicity and clarity by comparison:

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

I have not tested this because even reading it makes my eyes water...




回答3:


I would definitely look into Micah's suggestion which involves using a static singleton instance of your converter. But another thing to consider is that if you're using a separated presentation pattern like MVVM you can often avoid the requirement for a value converter by implementing the conversion in the ViewModel.

There's a lot of reasons you might want to do this.

For one, it is much more testable. Your unit tests can be sure that whatever is coming out of the ViewModel is what will be displayed by the UI. You can imagine testing a requirement that dollar values must follow the current culture's currency format, two decimals must be used, etc.

Another good reason is that exceptions in value converters will not be treated as validation errors which can be a huge pain in the butt in Silverlight. Even if you set ValidatesOnExceptions to true in the binding, if your value converter throws an exception, Silverlight will just let it propagate. If however you use the ViewModel to do the conversion, an exception will be treated as a validation error.

The downside is that you lose some of the "reusability" of a general purpose value converter.




回答4:


I don't know of a way to do this the way your are stating, but I just tried this as a sample and it worked. In your App.xaml.cs file you can create a method that uses reflection to load the converters.

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

Then you can use the converter with like this, half way there I guess.

<Button Width="{Binding Width, Converter={StaticResource TrivialFormatter}}" />

The problem with the approach you are proposing is that the Xaml parser doesn't know when and how many instances of your converter to create. Creating it as a resource ensure only one instance.



来源:https://stackoverflow.com/questions/2304269/using-value-converters-in-wpf-without-having-to-define-them-as-resources-first

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!