WPF ValueConverter - Standard return for unconvertible value
Asked Answered
J

6

47

Over the course of the last year or so I have seen many different value converters for many different purposes, from many different authors. One thing that sticks out in my mind is the wide variance of the 'default' values that are returned by them. For example;

  public class MyConverter: IValueConverter
  {
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
      // OK, we test for some undesirable, unconvertable situation, typically null...
      if (value == null)
      {
        // And here are a variety of 'defaults' that I have seen, these begin the most typical.
        return null;
        return DependencyProperty.UnsetValue;
        return Binding.DoNothing;
      }
        //...... other code.. whatever...
}}

So my question is, is there a 'standard' way to indicate that an input value can't be converted?

Janie answered 13/5, 2011 at 13:40 Comment(0)
J
5

After much thinking and digging around, it seems that DependencyProperty.UnsetValue is the appropriate choice. I have moved everything in house over to this pattern with much success. Also, the text in the 'Remarks' section of this page indicates that I this is probably the best choice..

There is also some discussion about returning the input value if a binding can't be converted, but this can easily "break" the binding system. Think of a case where the binding input is a 'string' and the output is a 'brush'. Returning a string is not going to work!

Janie answered 7/10, 2011 at 19:23 Comment(1)
+1. Returning DependencyProperty.UnsetValue is the correct choice according to the documentation.Diaghilev
L
39

According to MSDN - IValueConverter:

The data binding engine does not catch exceptions that are thrown by a user-supplied converter. Any exception that is thrown by the Convert method, or any uncaught exceptions that are thrown by methods that the Convert method calls, are treated as run-time errors. Handle anticipated problems by returning DependencyProperty.UnsetValue.

The key line is Handle anticipated problems by returning DependencyProperty.UnsetValue.

Luge answered 10/10, 2011 at 14:52 Comment(2)
But what is the actual practical difference between DependencyProperty.UnsetValue and Binding.DoNothing? The docs are not really clear here. In what way does the binding engine behave differently in these two cases?Poetry
@bitbonk: See this answer: https://mcmap.net/q/372647/-what-are-the-special-values-of-wpf-39-s-binding-engine-when-converting-values ... basically, Binding.DoNothing halts the binding engine in its tracks, whereas DependencyProperty.UnsetValue tells the binding engine to use the FallbackValue instead.Luge
F
25

When you look these values up you will find out what they mean. Then pick the right one to return in your converter.

The main issue is that null might be a valid value for the property.

DependencyProperty.UnsetValue to indicate that the property exists, but does not have its value set by the property system

Binding.DoNothing to instruct the binding engine not to transfer a value to the binding target, not to move to the next Binding in a PriorityBinding, or not to use the FallBackValue or default value

EDIT

To indicate that you can't convert the value you should simply return the given value. That is the best you can do because it returns the problem to the author of the binding. If you meddle with the value it becomes very hard to findout what is going on.

Falgoust answered 13/5, 2011 at 13:48 Comment(5)
OK, that make sense. I guess that in many cases this will wind up being an exception. Do you think that throwing an exception inside of the converter itself would be a better approach?Janie
No. Never break a binding. See: #2454245 and #4945053Falgoust
Well it seems that the consensus is to return DependencyProperty.UnsetValueJanie
That is certainly a downside of UnsetValue, but returning it will allow usage of 'FallbackValue' on the binding, allowing the end user to decide what the 'default' should be. Also, there are some special scenarios where the value is useful: msdn.microsoft.com/en-us/library/ms745795.aspx#Advanced At the end of the day I am trying to come up with a reasonable, and flexible standard for my organization.Janie
+1 for returning DependencyProperty.UnsetValue. If you do that, WPF shows a validation error and the error message is "Value '...' could not be converted". Exactly what I was looking for. Although WPF behaves the same when you simply return the unconverted value.Diaghilev
J
5

After much thinking and digging around, it seems that DependencyProperty.UnsetValue is the appropriate choice. I have moved everything in house over to this pattern with much success. Also, the text in the 'Remarks' section of this page indicates that I this is probably the best choice..

There is also some discussion about returning the input value if a binding can't be converted, but this can easily "break" the binding system. Think of a case where the binding input is a 'string' and the output is a 'brush'. Returning a string is not going to work!

Janie answered 7/10, 2011 at 19:23 Comment(1)
+1. Returning DependencyProperty.UnsetValue is the correct choice according to the documentation.Diaghilev
G
2

what you return as a default depends on the situation. You don't want to return an int as the default for a converter to a bool, or return a bool for a converter for the visibility enum.

Glance answered 13/5, 2011 at 13:50 Comment(0)
T
0

Usually if a value can't be converted, I throw an Exception

This is because if I'm trying to convert a value using an invalid converter, I'd like to be alerted of it so I can alter my code.

In some rare cases, a value may be valid even though it can't be converted, and in that case I usually return the same value that was passed to the converter. This is only used if I want the value to be converted if possible, or to stay the same if not.

Another rare case that I've done on occasion is hardcoding a default value. This is usually done when I know the Converter may be used with an invalid parameter, and I want to return a valid value no matter what the result is. My hard-coded default converters almost always return boolean values.

I don't think I have ever returned any of the 3 you specified (null, DependencyProperty.UnsetValue, or Binding.DoNothing) because those values are often unexpected and not easy to notice unless you specifically look for them.

Therefrom answered 7/10, 2011 at 19:36 Comment(1)
Yeah, possibly, but I think that most of the community, etc. agrees that breaking the binding system (by throwing an exception) is the wrong way to go. I had a crashing designer on me about a thousand times when I used that approach, or runtime crashing which is even worse....Janie
G
-4

You could also return a real targetType default object by using this function:

public static object GetDefault(Type type)
{
   if(type.IsValueType)
   {
      return Activator.CreateInstance(type);
   }
   return null;
}

Source: C# - Programmatic equivalent of default(Type)

Gerontology answered 13/5, 2011 at 15:3 Comment(1)
This is bad: it will hide the problem.Falgoust

© 2022 - 2024 — McMap. All rights reserved.