views:

406

answers:

2

I have a class, called DateField, that has a string Value property. If you set this property to a string that can be parsed into a valid date, the property setter sets Value to the properly formatted date, e.g.:

    private string _Value;
    public string Value
    {
        get
        {
            return _Value;
        }
        set
        {
            if (value == _Value)
            {
                return;
            }
            object result;
            if (TryParse(value, out result))
            {
                _Value = Format(result);
            }
            else
            {
                _Value = value;
            }
            OnPropertyChanged("Value");
        }
    }

I create a TextBox that's bound to this field:

    <DataTemplate DataType="{x:Type m:DateField}">
        <TextBox                                         
                IsTabStop="True"
                Text="{Binding Value, Mode=TwoWay, ValidatesOnDataErrors=True}">
        </TextBox>
    </DataTemplate>

When I enter, say, "010109" into this field and tab out of it, the Binding appropriately sets the Value property to this string. The property setter runs, _Value gets correctly set to "01/01/2009" (the TryParse implementation in this class is a little more catholic in what it accepts than DateTime.TryParse is), and the PropertyChanged event gets raised. I know this last bit is happening because another object that's subscribed to the list gets updated.

But the TextBox doesn't. Why not? I've set Value, I've raised PropertyChanged; what more do I need to be doing?

+2  A: 

I think you should use a converter and implement both the Convert and the ConvertBack methods

Natrium
Done; see my answer for details.
Robert Rossney
A: 

I think I have this working properly, but I'm not entirely happy with how I've done it.

The typical pattern for using a ValueConverter is that the ConvertBack should return the converted value if parsing succeeded, and DependencyProperty.UnsetValue if it failed. I can't do that. If I do that, the bound Value property doesn't get set. So the value doesn't get validated, and no validation error doesn't shows up in the UI.

What I've done instead is implemented a DateValueConverter class whose ConvertBack method returns either the parsed DateTime, or the string that it unsuccessfully tried to convert. The Value property in my DateTimeField class (actually, in the Field class it's derived from) looks like this:

public object Value
{
    get
    {
        return _Value;
    }
    set
    {
        if (value == _Value)
        {
            return;
        }

        if (!Validate(value))
        {
            return;
        }

        _Value = value;
        OnPropertyChanged("Value");
    }
}

The Validate method basically just looks at the type of the value being passed in: if it's a DateTime, then it's valid; if it's a string, it's not.

I'm not happy with this because it seems like a ValueConverter shouldn't convert a value into two different types. It feels like a hack. But maybe it's okay. I need to think about this some more.

Robert Rossney