WPF ComboBox SelectedItem - 更改为以前的值

问题描述 投票:0回答:5

我有一个 ComboBox,其中 SelectedItem 绑定到 ViewModel。

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

当用户在视图组合框中选择一个新项目时,我想显示一条提示并验证他们是否想要进行更改。

在视图模型的 SetItem 属性设置器中,我显示一个对话框来确认选择。当他们说“是”时,效果就很好。

我的问题是,当用户单击“否”时,我不确定谁可以获得组合框 恢复到之前的值。 ViewModel 中的属性具有正确的 较旧的值,但是在视图中,组合框显示新选择的值。

我希望用户选择一个项目,确认他们想要继续操作,如果他们愿意 决定不这样做,我希望组合框恢复到上一个项目。

我怎样才能做到这一点? 谢谢!

wpf combobox selecteditem
5个回答
26
投票

当用户说“不”时,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 将在处理完选择更改事件后处理此消息,因此将视图中的值恢复为应有的值。 您的虚拟机显然需要访问当前的

Dispatcher

。如果您需要一些有关如何执行此操作的指示,请参阅有关 VM 基类的

我的博客文章


14
投票

我整理了一个小样本来找出原因。我必须添加实际上临时更改底层成员变量值的代码,以便当 WPF 重新查询 getter 时,它会看到值发生了变化。否则,UI 无法正确反映取消,BeginInvoke() 调用不会执行任何操作。

这是我的博客文章

,其中我的示例显示了非工作和工作实现。 我的二传手最终看起来像这样:

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



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;



1
投票

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; } } }

或者在你的ViewModel中:

Synchronization.Current.Post(new SendOrPostCallback(Validate), null);



0
投票

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

	
© www.soinside.com 2019 - 2024. All rights reserved.