Windows Phone Runtime 8.1 (WinRT) 自带了DatePicker和TimePicker控件。妈妈再也不用担心我装WPToolkit了。但是和WPToolkit里面的两个Picker不同,WinRT的控件在MVVM模式里做data binding的时候是要爆的。

首先是DatePicker。

具体的情况表现为:ViewModel里的属性是DateTime类型,并且VM正确实现了INotifyPropertyChanged接口,前台直接用Binding语法绑定这个属性,但VM变化,界面不变。界面变化,VM不变。代码看起来就像是这样:

Xaml:

<DatePicker Date="{Binding SelectedDate, Mode=TwoWay}" />

ViewModel:

private DateTime _selectedDate;

public DateTime SelectedDate
{
    get { return _selectedDate; }
    set { _selectedDate = value; RaisePropertyChanged(); }
}

经过一番苦逼的开荒,发现WP8.1的DatePicker的Date属性,其实不是DateTime类型的。而是DateTimeOffset!(草草草草草

所以我们得写一个Converter,用来把DateTime和DateTimeOffset互转。

public class DateTimeToOffsetConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        try
        {
            var date = (DateTime)value;
            return new DateTimeOffset(date);
        }
        catch (Exception ex)
        {
            return DateTimeOffset.MinValue;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        try
        {
            var dto = (DateTimeOffset)value;
            return dto.DateTime;
        }
        catch (Exception ex)
        {
            return DateTime.MinValue;
        }
    }
}

把它撸在App.xaml里,这样就全局都能用了:

<Application x:Class="DateDiffer.WinRT.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:DateDiffer.WinRT"
             xmlns:converters="using:DateDiffer.WinRT.Converters">
    <Application.Resources>
        .........
        <converters:DateTimeToOffsetConverter x:Key="DateTimeToOffsetConverter" />
    </Application.Resources>
</Application>

然后ViewModel不用改,改Xaml就行:

<DatePicker Date="{Binding SelectedDate, Mode=TwoWay, Converter={StaticResource DateTimeToOffsetConverter}}" />

现在妈妈再也不用担心数据绑定了!

另一个坑是TimePicker,故障情况和DatePicker类似。TimePicker的Time属性其实是TimeSpan类型的。

最简单的改法是把ViewModel里对于的属性类型改成TimeSpan。

private TimeSpan _selectedTime;

public TimeSpan SelectedTime
{
    get { return _selectedTime; }
    set { _selectedTime = value; RaisePropertyChanged(); }
}
<TimePicker Time="{Binding SelectedTime, Mode=TwoWay}" />

不要试图在Xaml里绑定一个DateTime类型的TimeOfDay属性。会爆的,不信你可以自己作死一下。

最后我们要获得用户选择的时间日期时候应该这样,代码虽然2了点,但结果肯定正确:

var sourceDtm = new DateTime(SelectedDate.Year, SelectedDate.Month, SelectedDate.Day, SelectedTime.Hours, SelectedTime.Minutes, SelectedTime.Seconds); 

不能这样:

SelectedDate.AddTicks(SelectedTime.Ticks);

不信你也可以自己作死一下。