2010-04-06 32 views
18

我有一個組合框,將SelectedItem綁定到ViewModel。WPF組合框SelectedItem - 更改爲以前的值

<ComboBox SelectedItem="{Binding SelItem, Mode=TwoWay}" ItemsSource="{Binding MyItems}"> 

當用戶選擇查看組合框一個新的項目,我想顯示一個提示並確認他們希望做出改變。

在View Model的SetItem Property setter中,我顯示一個對話框來確認選擇。當他們說是的,它工作正常。

我的問題是,當用戶點擊「否」時,我不確定誰能讓ComboBox 恢復到以前的值。 ViewModel中的屬性具有正確的 舊值,但在視圖中,ComboBox顯示新選定的值。

我想要用戶選擇一個項目,確認他們想要繼續它,如果他們 決定不,我希望組合框恢復到以前的項目。

我該如何做到這一點? 謝謝!

回答

20

當用戶說「不」時,WPF不知道該值已更改。就WPF而言,值是用戶選擇的任何值。

您可以嘗試提高屬性更改通知:

public object SelItem 
{ 
    get { ... } 
    set 
    { 
     if (!CancelChange()) 
     { 
      this.selItem = value; 
     } 

     OnPropertyChanged("SelItem"); 
    } 
} 

的問題是,在變更通知發生在評選活動的在同一範圍內。因此,WPF忽略它,因爲它已經知道屬性已經改變 - 用戶選擇的項目!

你需要做的是在一個單獨的消息擡高通知事件:

public object SelItem 
{ 
    get { ... } 
    set 
    { 
     if (CancelChange()) 
     { 
      Dispatcher.BeginInvoke((ThreadStart)delegate 
      { 
       OnPropertyChanged("SelItem"); 
      }); 
      return; 
     } 

     this.selItem = value; 
     OnPropertyChanged("SelItem"); 
    } 
} 

那麼WPF將它做處理選擇更改事件之後,因此將恢復在價值處理此消息回顧它應該是什麼。

您的VM顯然需要訪問當前的Dispatcher。如果您需要關於如何執行此操作的指示信息,請參閱基礎VM類上的my blog post

+0

這真是棒極了 - 謝謝!我不確定如何重新發送消息以便View更新。 – 2010-04-06 18:28:58

+1

由於[WPF 4.0中的更改](https://karlshifflett.wordpress.com/2009/05/27/wpf-4-0-data-binding-change-great-feature/)請按照更多[完整解決方案@ NathanAW](http://stackoverflow.com/a/2709931/197371) – 2015-05-04 20:19:59

1

另一種方式來做到這一點(請確保您也可以參考意見):

http://amazedsaint.blogspot.com/2008/06/wpf-combo-box-cancelling-selection.html

從鏈接: 事件處理程序的遞歸調用沒有全局變量的問題的另一個解決方案是取消處理程序在編程選擇更改之前分配,然後重新分配。

例:

cmb.SelectionChanged -= ComboBox_SelectionChanged; 
cmb.SelectedValue = oldSel.Key; 
cmb.SelectionChanged += ComboBox_SelectionChanged; 
11

感謝這個問題和答案。 Dispatcher.BeginInvoke幫助了我,並且是我最終解決方案的一部分,但上述解決方案在我的WPF 4應用程序中並不起作用。

我整理了一個小樣本來找出原因。我不得不添加實際上改變了底層成員變量值的代碼,以便當WPF重新查詢getter時,它會看到該值變爲。否則,UI沒有正確反映取消,而BeginInvoke()調用沒有做任何事情。

Here's a my blog post與我的示例顯示非工作和工作的實現。

我二傳手結束這樣看:

private Person _CurrentPersonCancellable; 
    public Person CurrentPersonCancellable 
    { 
     get 
     { 
      Debug.WriteLine("Getting CurrentPersonCancellable."); 
      return _CurrentPersonCancellable; 
     } 
     set 
     { 
      // Store the current value so that we can 
      // change it back if needed. 
      var origValue = _CurrentPersonCancellable; 

      // If the value hasn't changed, don't do anything. 
      if (value == _CurrentPersonCancellable) 
       return; 

      // Note that we actually change the value for now. 
      // This is necessary because WPF seems to query the 
      // value after the change. The combo box 
      // likes to know that the value did change. 
      _CurrentPersonCancellable = value; 

      if (
       MessageBox.Show(
        "Allow change of selected item?", 
        "Continue", 
        MessageBoxButton.YesNo 
       ) != MessageBoxResult.Yes 
      ) 
      { 
       Debug.WriteLine("Selection Cancelled."); 

       // change the value back, but do so after the 
       // UI has finished it's current context operation. 
       Application.Current.Dispatcher.BeginInvoke(
         new Action(() => 
         { 
          Debug.WriteLine(
           "Dispatcher BeginInvoke " + 
           "Setting CurrentPersonCancellable." 
          ); 

          // Do this against the underlying value so 
          // that we don't invoke the cancellation question again. 
          _CurrentPersonCancellable = origValue; 
          OnPropertyChanged("CurrentPersonCancellable"); 
         }), 
         DispatcherPriority.ContextIdle, 
         null 
        ); 

       // Exit early. 
       return; 
      } 

      // Normal path. Selection applied. 
      // Raise PropertyChanged on the field. 
      Debug.WriteLine("Selection applied."); 
      OnPropertyChanged("CurrentPersonCancellable"); 
     } 
    } 
+2

我已經在我的setter中完成了這項工作。這不適合我。 – Virus 2013-01-03 06:26:39

+0

你使用什麼版本的.net?你看到什麼行爲? – NathanAW 2013-01-06 13:06:13

1

我這樣做是爲了讓變化經歷和在在調度BeginInvoked拉姆達執行驗證的方式。

public ObservableCollection<string> Items { get; set; } 
    private string _selectedItem; 
    private string _oldSelectedItem; 
    public string SelectedItem 
    { 
     get { return _selectedItem; } 
     set { 
      _oldSelectedItem = _selectedItem; 
      _selectedItem = value; 
      if (PropertyChanged != null) 
      { 
       PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem")); 
      } 
      Dispatcher.BeginInvoke(new Action(Validate));     
     } 
    } 

    private void Validate() 
    {    
     if (SelectedItem == "Item 5") 
     { 
      if (MessageBox.Show("Keep 5?", "Title", MessageBoxButton.YesNo) == MessageBoxResult.No) 
      { 
       SelectedItem = _oldSelectedItem; 
      } 
     } 
    } 

或在您的視圖模型:

Synchronization.Current.Post(new SendOrPostCallback(Validate), null); 
相關問題