WPF ComboBox SelectedItem - 更改为以前的值

Rob*_*ler 20 wpf combobox selecteditem

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

<ComboBox SelectedItem="{Binding SelItem, Mode=TwoWay}" ItemsSource="{Binding MyItems}">
Run Code Online (Sandbox Code Playgroud)

当用户在View ComboBox中选择一个新项目时,我想显示一个提示并确认他们想要进行更改.

在视图模型的SetItem属性设置器中,我显示一个对话框以确认选择.当他们说是的时候,它运作正常.

我的问题是,当用户点击"否"时,我不确定是谁让ComboBox恢复到之前的值.ViewModel中的Property具有正确的旧值,但在View中,ComboBox显示新选择的值.

我希望用户选择一个项目,确认他们要继续使用它,如果他们决定不这样做,我希望ComboBox恢复到上一个​​项目.

我怎么能做到这一点?谢谢!

Ken*_*art 26

当用户说"不"时,WPF不知道值已经改变.就WPF而言,值是用户选择的任何值.

您可以尝试提出属性更改通知:

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

        OnPropertyChanged("SelItem");
    }
}
Run Code Online (Sandbox Code Playgroud)

问题是,更改通知发生在选择事件的同一上下文中.因此,WPF忽略它,因为它已经知道属性已经改变 - 用户选择的项目!

您需要做的是在单独的消息中引发通知事件:

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

        this.selItem = value;
        OnPropertyChanged("SelItem");
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,WPF将处理完选择更改事件处理此消息,并因此将视图中的值恢复为应该的值.

您的VM显然需要访问当前的Dispatcher.如果您需要有关如何执行此操作的指示,请参阅在基本VM类上的博客文章.


Nat*_*nAW 13

感谢您提出这个问题和答案.Dispatcher.BeginInvoke帮助了我,并且是我最终解决方案的一部分,但上面的解决方案在我的WPF 4应用程序中不起作用.

我把一个小样本放在一起找出原因.我必须添加实际上暂时更改底层成员变量值的代码,这样当WPF重新查询getter时,它会看到值被chaned.否则,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");
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 我在我的二传手中完成了这个.这不适合我. (3认同)