mercredi 6 mai 2015

IValueConverter.ConvertBack not firing

I want to make my own DateTimePicker (WhenView) and have it two-way bind to a yyyyMMddHHmm string. I'm relatively new to XAML so may be missing something basic!

Control Model: (When)

public class When : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    int _yea; public int Yea { get { return _yea; } set { _yea = value; PropertyChanged(this, new PropertyChangedEventArgs("Yea")); } }
    int _mon; public int Mon { get { return _mon; } set { _mon = value; PropertyChanged(this, new PropertyChangedEventArgs("Mon")); } }
    int _day; public int Day { get { return _day; } set { _day = value; PropertyChanged(this, new PropertyChangedEventArgs("Day")); } }
    int _hou; public int Hou { get { return _hou; } set { _hou = value; PropertyChanged(this, new PropertyChangedEventArgs("Hou")); } }
    int _min; public int Min { get { return _min; } set { _min = value; PropertyChanged(this, new PropertyChangedEventArgs("Min")); } }
    int _sec; public int Sec { get { return _sec; } set { _sec = value; PropertyChanged(this, new PropertyChangedEventArgs("Sec")); } }

    public When()
        : this(DateTime.Now)
    {
    }

    public When(DateTime dt)
    {
        Yea = dt.Year;
        Mon = dt.Month;
        Day = dt.Day;
        Hou = dt.Hour;
        Min = dt.Minute;
        Sec = dt.Second;
    }

    public DateTime ToDateTime()
    {
        return new DateTime(Yea, Mon, Day, Hou, Min, Sec);
    }
}

Control View: (WhenView)

<UserControl x:Class="DateBind.WhenView"
         xmlns="http://ift.tt/o66D3f"
         xmlns:x="http://ift.tt/mPTqtT"
         xmlns:mc="http://ift.tt/pzd6Lm" 
         xmlns:d="http://ift.tt/pHvyf2" 
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300">
<StackPanel Margin="16">
    <TextBox Text="{Binding Yea, Mode=TwoWay}" />
    <TextBox Text="{Binding Mon, Mode=TwoWay}" />
    <TextBox Text="{Binding Day, Mode=TwoWay}" />
    <TextBox Text="{Binding Hou, Mode=TwoWay}" />
    <TextBox Text="{Binding Min, Mode=TwoWay}" />
    <TextBox Text="{Binding Sec, Mode=TwoWay}" />
</StackPanel>

IValueConverter: (WhenConverter) To facilitate binding to a string:

    [ValueConversion(typeof(string), typeof(When))]
public class WhenConverter : IValueConverter
{
    const string Format = @"yyyyMMddHHmm";

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is string)
        {
            DateTime parsedDate = DateTime.ParseExact(value as string, Format, null);
            return new When(parsedDate);
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value is When)
        {
            if (targetType == typeof(string))
            {
                return ((When)value).ToDateTime().ToString(Format);
            }
        }

        return null;
    }
}


So that's the building blocks done.

MainWindow Code-behind I'm storing the Date string in the MainWindow for brevity, it's in a data class in my real application.

    public partial class MainWindow : Window, INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    string _date;
    public string Date 
    {
        get { return _date; } 
        set { _date = value; PropertyChanged(this, new PropertyChangedEventArgs("Date")); } 
    }

    public MainWindow()
    {
        InitializeComponent();
        Date = "1234" + "01" + "02" + "0101";
        DataContext = this;
    }
}

MainWindow XAML: (I've added a simple TextBox for testing purposes.)

<Window x:Class="DateBind.MainWindow"
    xmlns="http://ift.tt/o66D3f"
    xmlns:x="http://ift.tt/mPTqtT"
    Title="MainWindow" Height="350" Width="525"
    xmlns:local ="clr-namespace:DateBind">
<StackPanel>
    <StackPanel.Resources>
        <local:WhenConverter x:Key="WhenConverter"></local:WhenConverter>
    </StackPanel.Resources>
    <local:WhenView DataContext="{Binding Date, Converter={StaticResource WhenConverter}, Mode=TwoWay}"></local:WhenView>
    <TextBox Text="{Binding Date}"></TextBox>
</StackPanel>

What works:

  • TextBox and WhenControl is initialised with the initial Date successfully
  • Updating the value in the TextBox updates WhenControl successfully

The problem:

  • Updating any value in the WhenControl does not update the TextBox (and therefore I expect, the underlying data value)
  • PropertyChanged is getting fired within the When class, but I don't know what else to do to have it make the TextBox/underlying data update.

Aucun commentaire:

Enregistrer un commentaire