2012-05-01 56 views
2

我目前遇到了WP7的TimePicker問題,特別是將它綁定到ViewModel。有問題的TimePicker設置鬧鐘的時間。第一次加載頁面時,TimePicker會正確顯示Alarm對象的值(在這種情況下,默認值爲12:00 am)。但是,當用戶選擇一個新值時,這並不反映在模型中 - 它會覆蓋上午12:00的值。WP7:TimePicker綁定沒有用新值更新

我使用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}" /> 

(視圖模型)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設置器被調用兩次。通過添加下面的調試行的時間特性:時間設定爲上午9:10時

[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"); 
      } 
     } 
    } 

下輸出日誌中產生:

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 
+1

你不清楚哪些是你的ViewModel和DataContext。 – Robaticus

+1

AlarmEditorModel.cs是ViewModel,它的一個實例作爲DataContext傳遞給AlarmEditorControl(View)的一個實例。 –

+1

愚蠢的問題,但在這一行不同的值:if(_time!= value)? –

回答

1

問題解決了,我認爲。我需要進行額外的支票OnNavigatedTo爲了獲得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 
     ... 

需要做這個解決方案多試驗幾次,但它迄今似乎在做這項工作。