'Brush' type does not have a public TypeConverter class.
I’ve been a big fan of Value Converters in WPF for some time now, but I was bitten today by something simple and thought it would be worth sharing.
Brush Converter
One of my favorite uses for Value Converters is to set colors of things based on object state. In my current application, I have drawn a circle that I want to be filled in Red if the application is not connected to the database, and green if it is connected. My binding engine has an “IsDatabaseConnected” boolean property that I can use for the binding, so what I need to do is bind the bool to a Brush. To do this, we create a simple converter:
using System.Windows.Data; using System.Drawing; namespace CamraSketchViewerWPF { public class DatabaseConnectedColorConverter : IValueConverter { public Brush ConnectedBrush { get; set; } public Brush NotConnectedBrush { get; set; } #region IValueConverter Members public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { if (value is bool) { var isConnected = (bool) value; return isConnected ? ConnectedBrush : NotConnectedBrush; } return null; } public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new System.NotImplementedException(); } #endregion } }
In the XAML we need an instance of the Converter to bind to: I used Blend 3 to write the XAML, but whether you do it this way or write it by hand you should end up with something like this:
<local:DatabaseConnectedColorConverter x:Key="DatabaseConnectedColorConverter" />
This will create an instance of the Converter as a resource that can then be used for the actual binding:
<Ellipse Fill="{Binding IsDatabaseConnected, Converter={StaticResource DatabaseConnectedColorConverter}, Mode=Default}" Width="15" Height="15"/>
If you run the code like so, you will get a transparent circle. What’s missing are the property value declarations for the Converter. In addition to declaring the instance in XAML, we can also set its properties in XAML like so:
<local:DatabaseConnectedColorConverter x:Key="DatabaseConnectedColorConverter" ConnectedBrush="{StaticResource GreenBrush}" NotConnectedBrush="Red" />
Note that for ConnectedBrush I have defined my own version of Green as a resource. Now, if you run this code, you’ll receive the same exception that bit me:
‘Brush’ type does not have a public TypeConverter class.
It’s always the simplest things…
I have run into this message and others like it, and it is always frustrating. What it means is that the Type I am trying to descibe in XAML does not have TypeConverter behavior defined: this is what allows simple Strings in XAML to be properly transcribed into correct types at runtime.
In this case, the problem was a simple one but not an evident one. Now I love code completion and refactoring tools as much as the next guy, so whenever Intellisense volunteers to help me out I am quick to accept the assistance. In this case, however, it did more harm than good!
When I referenced the Brush in my Value Converter class code, I was prompted by Intellisense to resolve the missing namespace, which I did with the handy-dandy Shift-Alt-F10 keystoke. Only I did it reflexively and did not actually read my options. If you look at the code above, you will see that the Value Converter class is referencing the System.Drawing namespace instead of the System.Windows.Media namespace. System.Drawing.Brush was not written for WPF and so does not have the TypeConverter code necessary for this to work. The problem is easily corrected by changing the namespace appropriately.
Conclusion
I placed this in the “Read your options” file for future use. If you are interested in more TypeConverter details, check out this article by Rob Relyea at XAMLfied.
You should also decorate your converter class with the ValueConversionAttribute. It isn’t required, but it makes designers happier – and it documents what your converter does with compile time meta data.
Kevin,
I wasn’t aware of it but I’ll be using it from now on.
Thanks!
Thanks. I ran into the same problem and your article saved me.