2011-05-04 51 views
3

我有類似的東西會彈出給用戶以獲取確認更改。如果他點擊否,我將視圖模型中的selectedValue設置爲之前的選擇。但它沒有正確顯示在視圖中。請幫忙。如何使用WPF MVVM回滾選定組合框的SelectedValue

+1

請顯示一些代碼。 – Jon 2011-05-04 07:20:09

+0

.xaml代碼: gowri 2011-05-04 07:28:14

+0

.cs(ViewModel)ComSelectedValue = SomeCodeoftheItemsSource;它沒有改變顯示的選定值 – gowri 2011-05-04 07:29:58

回答

0

假設:
- 當用戶從ComboBox中選擇某個值時,顯示一個對話框(帶有消息和OKCancel按鈕)。
- 如果用戶按下確定,一切正常。 :)
- 如果用戶按Cancel,則表示vmPropSelectedValue = previousValue。

這不起作用。爲什麼?

還沒有確切的答案,但我相信,當你顯示對話框系統已經只是改變了選擇的值和剛剛通知的來源(通過結合基礎設施)關於改變的值。如果此時(當源代碼擁有控制權時),您現在從您的VM代碼中更改ViewModel屬性的值,您希望觸發OnPropertyChanged的INotifyPropertyChanged,您希望WPF使用所請求的值更新目標。但是,WPF尚未完成整個週期 - 它仍在等待Source將控制權還給它。所以它只是拒絕你的請求(否則它會進入無限循環)。

如果這是混亂的,試試這個:
週期的開始:在UI
1.用戶更改值。 WPF改變目標。
2.綁定基礎架構請求源自行更新。
3.源更新本身(VM屬性)。
4.來源將控制返回到綁定的基礎。
週期結束。

專家:在這方面找不到一些文件。以上是我相信事情是如何運作的。如果不正確,請糾正。


答案很簡單:
AFAIK,這無法通過純粹的VM代碼獨自完成。你將不得不放置一些代碼隱藏代碼。
這裏有一種方法:http://www.amazedsaint.com/2008/06/wpf-combo-box-cancelling-selection.html

+0

我第二什麼publicgk說。您無法在綁定事務中更改該值。即使您管理更改值(比如通過OnPropertyChanging事件),用戶界面仍然會繼續,並且無視您的注意,除非您取消設置並重置DataContext,而這是很討厭的。所以你必須像上面的鏈接那樣弄髒一點,它實際上就像我認爲的那樣乾淨。 – 2011-05-04 09:54:53

0

在大多數WPF應用程序中,您使用雙向模式將視圖模型綁定到用戶界面,然後設置好。

但是,這違背了典型的用戶體驗,即當您編輯某些內容並且未保存時,即使您未將更改保存到數據庫中,也不會在整個應用程序中看到該編輯的反映。

WPF中可用的機制是Binding的UpdateSourceTrigger屬性。通過此屬性,您可以控制用戶界面何時更新其綁定的ViewModel。這允許您僅在用戶保存他正在編輯的內容或類似內容時才進行更新。

的XAML與UpdateSourceTrigger綁定一個例子設定明確:

"{Binding Path=Privado, UpdateSourceTrigger=Explicit, Mode=TwoWay}" 

而當你想真正保存到視圖模型您撥打:

UpdateSource(); 
5

如果用戶點擊不和您嘗試恢復該值,然後調用OnPropertyChanged,WPF將吞服該事件,因爲它已經響應該事件。解決此問題的一種方法是使用調度程序並在當前事件上下文外調用事件。

System.Windows.Threading.Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => { OnPropertyChanged("ComSelectedValue"); }), null); 
+0

這工作,但我不相信你必須這樣做。當然有一個更好的方法來做到這一點? – 2015-05-28 18:32:42

4

WPF似乎在更新UI之前驗證綁定屬性已更改。所以簡單地調用一個NotifyPropertyChanged()/ OnPropertyChanged()並不能解決問題。

問題是,由於屬性沒有改變,WPF不認爲它需要刷新組合框。

這是我在ViewModels中處理它的難以置信的方式;

不漂亮,但它的工作可靠。

0

如果您試圖異步引發屬性更改事件,該怎麼辦?這與shaun和NebulaSleuth的例子很相似。

public int SomeProperty 
    { 
    get { return m_someProperty; } 
    set 
    { 
     if (value == m_someProperty) 
      return; 

     if (doYesNo() == No) 
     { 
      // Don't update m_someProperty but let the UI know it needs to retrieve the value again asynchronously. 
      Application.Current.Dispatcher.BeginInvoke((Action) (() => NotifyOfPropertyChange("SomeProperty"))); 
     } 
     else 
     { 
      m_someProperty = value; 
      NotifyOfPropertyChange("SomeProperty"); 
     } 
    } 
    } 
0

這裏是我使用的一般流程:

  1. 我只是讓改變通過視圖模型和跟蹤任何在之前通過的。 (如果您的業務邏輯要求所選項目不處於無效狀態,建議將其移至模型側)。這種方法對使用單選按鈕呈現的ListBox也很友好,因爲儘快使SelectedItem設置者退出並不會阻止單選按鈕在消息框彈出時突出顯示。
  2. 我立即撥打了OnPropertyChanged事件無論在傳遞價值的
  3. 我放在一個處理任何撤銷邏輯和調用使用SynchronizationContext.Post() (BTW:SynchronizationContext.Post也適用於Windows應用商店。所以如果你有共享的ViewModel代碼,這種方法仍然有效)。

    public class ViewModel : INotifyPropertyChanged 
    { 
        public event PropertyChangedEventHandler PropertyChanged; 
    
        public List<string> Items { get; set; } 
    
        private string _selectedItem; 
        private string _previouslySelectedItem; 
        public string SelectedItem 
        { 
         get 
         { 
          return _selectedItem; 
         } 
         set 
         { 
          _previouslySelectedItem = _selectedItem; 
          _selectedItem = value; 
          if (PropertyChanged != null) 
          { 
           PropertyChanged(this, new PropertyChangedEventArgs("SelectedItem")); 
          } 
          SynchronizationContext.Current.Post(selectionChanged, null); 
         } 
        } 
    
        private void selectionChanged(object state) 
        { 
         if (SelectedItem != Items[0]) 
         { 
          MessageBox.Show("Cannot select that"); 
          SelectedItem = Items[0]; 
         } 
        } 
    
        public ViewModel() 
        { 
         Items = new List<string>(); 
         for (int i = 0; i < 10; ++i) 
         { 
          Items.Add(string.Format("Item {0}", i)); 
         } 
        } 
    } 
    
0

我意識到這是一個老的文章,但似乎沒有人做過的正確方法。我使用System.Interactivity.Triggers和Prism來處理SelectionChanged事件並手動觸發SelectedItem。這將防止用戶界面和視圖模型中出現不希望的選定項目更改。

我的觀點:

<Window x:Class="Lind.WPFTextBlockTest.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:vm="clr-namespace:Lind.WPFTextBlockTest" 
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 
    xmlns:prism="clr-namespace:Microsoft.Practices.Prism.Interactivity;assembly=Microsoft.Practices.Prism.Interactivity" 
    Title="MainWindow" Height="649" Width="397"> 
<Window.DataContext> 
    <vm:MainWindowViewModel/> 
</Window.DataContext> 
<StackPanel> 
    <ComboBox ItemsSource="{Binding Data}" SelectedItem="{Binding SelectedData, Mode=OneWay}"> 
     <i:Interaction.Triggers> 
      <i:EventTrigger EventName="SelectionChanged"> 
       <prism:InvokeCommandAction Command="{Binding TryChangeSelectedData}"/> 
      </i:EventTrigger> 
     </i:Interaction.Triggers> 
    </ComboBox> 
</StackPanel> 

我的視圖模型(BindeableBase和DelegateCommand從棱鏡5):

public class MainWindowViewModel : BindableBase 
{ 
    public ObservableCollection<string> Data { get; private set; } 
    private string selectedData; 
    public string SelectedData 
    { 
     get { return selectedData; } 
     set 
     { 
      SetProperty(ref selectedData, value); 
     } 
    } 
    public DelegateCommand<SelectionChangedEventArgs> TryChangeSelectedData { get; private set; } 
    public MainWindowViewModel() 
    { 
     Data = new ObservableCollection<string>() { "Foo", "Bar", "Dick", "Head" }; 
     SelectedData = Data.First(); 
     TryChangeSelectedData = new DelegateCommand<SelectionChangedEventArgs>(args => 
     { 
      var newValue = args.AddedItems.Cast<string>().FirstOrDefault(); 
      if (newValue == "Dick") 
       this.OnPropertyChanged(() => this.SelectedData); 
      else 
       SelectedData = newValue; 
     }); 
    } 
} 
4

用於.NET 4.5.1+很簡單的解決方案:

<ComboBox SelectedItem="{Binding SelectedItem, Delay=10}" ItemsSource="{Binding Items}" /> 

它的作品對於大多數情況下我來說。 只需觸發NotifyPropertyChanged,無需賦值回滾。

+1

我喜歡這個回答最好。如果可以的話,我會多加註意。 – NielW 2016-12-22 01:09:40

相關問題