The following tip is not new; it is based on this post and its comments.
However, for the sake of completeness and for future reference I bring here the final version.
The question this posts tries to address is: Where to put value converters?
Normal Solution
Usually, the common place to put value converters is in the resources section. With this in place you can use the value converter with StaticResource syntax:
<UserControl.Resources>
<local:NotConverter x:Key="notConverter" />
</UserControl.Resources>
...
<StackPanel>
<Button IsEnabled="{Binding Converter={StaticResource notConverter}}" />
</StackPanel>
This means that every time you want to use the value converter you need to add it to the resources section. A better place is to put it in a global converters resource file, so the resource definition is only done once.
Creative Solution
In short, have your converter derive from MarkupExtension. This will avoid the question altogether.
The complete solution provides a generic base class you should derive from, ConverterMarkupExtension. The advantages of deriving from this class are:
- Your converter can be used as a markup extension. So the former code becomes:
<StackPanel>
<Button IsEnabled="{Binding Converter={local:notConverter}}" />
</StackPanel>
Specifically, no resource definition is needed. At all.
- Only one instance of your converter is used to provide the value (sort of singleton).
Note that every time the XAML compiler see a markup extension, it will create a new instance, BUT the following implementation always return the same single converter. If you are worried about all the short lived instances of the markup extension just consider that using StaticResource (another markup extension)would have create them anyway. So there is no additional stress on memory consumption.
- The base class provide default implementation for both IValueConverter and IMultiValueConverter methods. It throws NotImplementedException. This doesn’t seem much but helps shorten your converter code in the usual case when you implement only one conversion direction.
ConverterMarkupExtension, short version for clarity
public abstract class ConverterMarkupExtension<T> : MarkupExtension, IValueConverter, IMultiValueConverter
where T : class, new()
{
private static T _converter = null;
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (_converter == null)
{
_converter = new T();
}
return _converter;
}
#region IValueConverter Members
public virtual object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
public virtual object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
#region IMultiValueConverter Members
...
#endregion
Here you can get the full version of the code including lots of comments.
Using the base class
Following is an example of how to use ConverterMarkupExtension to implement your own converter:
using System;
using System.Windows.Data;
using System.Globalization;
namespace WPF.Common
{
/// <summary>
/// Returns the negation of the given boolean value
/// </summary>
public class NotConverter : ConverterMarkupExtension<NotConverter>
{
public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return !(bool)value;
}
}
}
Note that the value converter code remains practically the same, but you get the ability to use it as a markup extension and remove the "not implemented" section.
That’s it for now,
Arik Poznanski.
CodeProject
In my new job at Sela I came across an application ( written by a client) that needed refactoring. This app has so many coding errors I’ve decided it worth its own post.
Why not rewrite the application?
You could suggest to rewrite the application but I’m strongly against it. To understand why you MUST read the excellent article Things You Should Never Do by Joel Spolsky. Go ahead and read it, it’s more important then reading this post!
Code Duplication
Never write the same code twice. I know, it’s so obvious but nevertheless a common (bad) practice.
Every time you use copy/paste to copy more than one line inside the IDE you should consider to write a new function.
And no, don’t squeeze those four lines into one. It makes reading this line extremely hard and generally means you didn’t handle those null return values in case of errors.
Encapsulation: Public Fields
Never use public fields. Always wrap them with properties. The only exception to this rule is when you write interop code which uses structs with a definite layout.
Maintain class responsibility
This is OOD basics. Every class should have a specific responsibility. The responsibility should be reflected in the class name and should not be too large, meaning you should not put all your application code into the Application class.
For example, suppose you have several places in your app that manipulate folders. Instead of having similar folder manipulation code in 50 different places like: Application, Main Window, different controls etc. you should create some sort of FolderManipulation class that will be responsible on this topic.
This will also help future developers of the project to easily find functionality they need, instead of rewriting them (in a different way).
Comment
Please, comment. Even if you think the code is self explanatory. Write comments that explain what you are doing and not only how you do it.
Those comments will be proved useful in the future when you or your colleagues will need to update the code.
Also, avoid short names for variables. Prefer “xmlSerializer” over “ser”,
Happy Refactoring!
Arik Poznanski.