views:

261

answers:

4

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

+1  A: 

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.

bendewey
On a similar theme, you could create a markup extension which returns an instance of its argument type. Then you could write `Converter={local:InstanceOf {x:Type local:TrivialFormatter}}`. As you note, though, this would result in a separate instantiation for every binding, which is potentially wasteful (especially if used in the ItemTemplate for a large ItemsControl).
itowlson
+3  A: 

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.

micahtan
Nice trick with the markup extension! On your first example, though, don't you need to make a static instance of the VC, e.g. `{x:Static local:SomeConverter.Instance}`?
itowlson
This is a very good suggestion. When creating your own value converters you should always prefer to have them accept a ConverterParameter instead of having instance properties so that you can use a singleton instance like this. It's SO much easier than using resources. I usually call mine something like {x:Static Local:InvertedBooleanConverter.Default} or something.
Josh Einstein
@ itowlson -- yes on the instance - I've edited my response. Thx for the catch.
micahtan
+1  A: 

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

itowlson
This is a perfectly valid way of doing it too. But as you noted the verbosity of XAML is like the Ark of the Covenant and merely looking at it will devour your soul.
Josh Einstein
+2  A: 

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.

Josh Einstein