我目前遇到WP7的TimePicker问题,特别是将其绑定到ViewModel。有问题的TimePicker设置警报的时间。首次加载页面时,TimePicker会正确显示Alarm对象的值(在这种情况下,默认值为12:00 am)。但是,当用户选择新值时,这不会反映在模型中 - 它会被先前的上午12:00覆盖。
我正在使用MVVM创建此表单并保存数据绑定。有什么特别的,我做错了吗?
(查看)AlarmEditorControl.xaml
<TextBlock Height="30" HorizontalAlignment="Left" Margin="1,6,0,0" Name="lblAlarmTime" Text="Alarm Time:" VerticalAlignment="Top" Grid.Column="2" FontSize="26" />
<!-- Data binding isn't working for updates! -->
<toolkit:TimePicker HorizontalAlignment="Left" Margin="140,34,0,0" Name="tpAlarmTime" VerticalAlignment="Top" Width="161" Grid.Column="1" Grid.ColumnSpan="2" Value="{Binding Path=Time, Mode=TwoWay}" />
(ViewModel)AlarmEditorModel.cs
[DataContractAttribute]
public class AlarmEditorModel
{
private int _index;
[DataMemberAttribute]
public Alarm Alarm { get; set; }
[DataMemberAttribute]
public int Index
{
get
{
return _index;
}
set
{
_index = value;
}
}
public AlarmEditorModel(int index)
{
_index = index;
Alarm = new Alarm();
// Get the list of alarms
AlarmSerializer serializer = new AlarmSerializer();
// Check the index is in range
List<Alarm> alarms = serializer.AlarmList;
if (_index > -1 && index < alarms.Count)
{
Alarm = alarms[_index];
}
}
public void Commit()
{
// Get the current list of alarms
AlarmSerializer serializer = new AlarmSerializer();
List<Alarm> alarms = serializer.AlarmList;
// Replace our new value
alarms[_index] = Alarm;
serializer.AlarmList = alarms;
}
}
(型号)Alarm.cs
[DataContract]
public class Alarm : INotifyPropertyChanged
{
private bool _active;
private DateTime _time;
[DataMember]
public string Name { get; set; }
[DataMember]
public DateTime Time
{
get
{
return _time;
}
set
{
if (_time != value)
{
_time = value;
RaisePropertyChanged("Time");
}
}
}
[DataMember]
public AlarmFrequency Frequency { get; set; }
[DataMember]
public AlarmTone Tone { get; set; }
[DataMember]
public bool Active {
get {
return _active;
}
set {
_active = value;
}
}
public string AlarmTimeString {
get {
return Time.ToShortTimeString();
}
}
/**
* Default Constructor
*/
public Alarm()
{
Debug.WriteLine("Alarm: Using default constructor");
this.Name = "New Alarm";
this.Time = DateTime.Today;
this.Frequency = new AlarmFrequency();
this.Tone = new AlarmTone();
this.Active = true;
Debug.WriteLine("Alarm hours is " + this.Time.Hour);
}
/**
* Parameterised constructor
*/
public Alarm(string Name, DateTime Time, AlarmFrequency Frequency,
AlarmTone Tone, bool Active)
{
Debug.WriteLine("Alarm: Using parameterised constructor");
this.Name = Name;
this.Time = Time;
this.Frequency = Frequency;
this.Tone = Tone;
this.Active = Active;
}
}
(调用页面)NewAlarm.xaml.cs
private List<Channel> feeds;
private AlarmEditorModel _aem;
private int _index;
public NewAlarm()
{
InitializeComponent();
feeds = new List<Channel>();
feeds.Add(new Channel(null, null, "Feed 1", DateTime.Now));
feeds.Add(new Channel(null, null, "Feed 2", DateTime.Now));
}
/**
* Setup functions when the page is loaded
*/
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Function vars + debug
Debug.WriteLine("Navigating to");
// Check if we're recovering from tombstone
if (!StateUtilities.IsLaunching && this.State.ContainsKey("AlarmState"))
{
// Recover the saved model
_aem = (AlarmEditorModel)this.State["AlarmState"];
}
else
{
try
{
// Editing an alarm.
_index = Convert.ToInt32(this.NavigationContext.QueryString["index"]);
Debug.WriteLine("Editing an alarm");
}
catch (KeyNotFoundException knfe)
{
Debug.WriteLine(knfe.Message);
// No index provided, new alarm
_index = -1;
}
// Set the model from the index
_aem = new AlarmEditorModel(_index);
}
AlarmEditor.DataContext = _aem.Alarm;
Debug.WriteLine(_aem.Alarm.Time.Hour);
}
/**
* Preserve alarm details when tombstoning
*/
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
if (this.State.ContainsKey("AlarmState"))
{
this.State["AlarmState"] = _aem;
}
else
{
this.State.Add("AlarmState", _aem);
}
StateUtilities.IsLaunching = false;
}
编辑1
看起来Alarm.Time的setter被调用两次。通过将以下调试行添加到Time属性:
[DataMember]
public DateTime Time
{
get
{
return _time;
}
set
{
Debug.WriteLine("Current time is " + _time.ToShortTimeString());
Debug.WriteLine("New time is " + value.ToShortTimeString());
if (_time != value)
{
Debug.WriteLine("Changing time value");
_time = value;
RaisePropertyChanged("Time");
}
}
}
将时间设置为上午9:10时,日志中会生成以下输出:
Current time is 4:00 AM
New time is 9:10 AM
Changing time value
Current time is 12:00 AM
New time is 4:00 AM
Changing time value
答案 0 :(得分:1)
我认为问题已经解决了。在从Tombstone恢复时,我需要在OnNavigatedTo
中进行额外检查,以便在ViewModel覆盖之前获取TimePicker的值:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
// Check if we're recovering from tombstone
if (!StateUtilities.IsLaunching && this.State.ContainsKey("AlarmState"))
{
// Recover the saved model
_aem = (AlarmEditorModel)this.State["AlarmState"];
// Use the value from the TimePicker
_aem.Alarm.Time = (DateTime)AlarmEditor.tpAlarmTime.Value;
}
else
...
需要对此解决方案进行一些测试,但到目前为止它似乎正在完成这项工作。