当前位置: 动力学知识库 > 问答 > 编程问答 >

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

问题描述:

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}}" Height="50">

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

网友答案:

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.

网友答案:

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

网友答案:

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.

网友答案:

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.

分享给朋友:
您可能感兴趣的文章:
随机阅读: