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);
不信你也可以自己作死一下。