WPF ComboBox何时不应更改

时间:2016-06-30 13:40:31

标签: c# wpf combobox selectionchanged

我有一个雇主组合框。选择雇主后,将使用雇主特定数据填充表格:

        <ComboBox Name="EmployerListBox"
                  IsReadOnly="True"
                  ItemsSource="{Binding EmployerCollection, UpdateSourceTrigger=PropertyChanged}"
                  SelectedItem="{Binding SelectedEmployer, UpdateSourceTrigger=PropertyChanged}" 
                  Width="150" />

这是绑定它的属性,以及检查表是否脏的方法。如果表是脏的,则会提示用户如果更改雇主,则更改将丢失:

    /// <summary>
    /// Selected Employer
    /// </summary>
    public String SelectedEmployer
    {
        get
        {
            return _SelectedEmployer;
        }
        set
        {
            if (_SelectedEmployer != value && CanChangeEmployer())
            {
                _SelectedEmployer = value;
                NotifyPropertyChanged(m => m.SelectedEmployer);
                GetGarnishmentsTableView();
            }
        }
    }
    private String _SelectedEmployer = "";


    /// <summary>
    /// Method that executes each time user wants to change employers
    /// </summary>
    public Boolean CanChangeEmployer()
    {
        Boolean _returnValue = true;

        if (GarnishmentsTableIsDirty)
        {
            _returnValue = false;

            MessageBoxResult _change =
                MessageBox.Show("There are unsaved changes.  " +
                                "Changing Employers will lose any unsaved changes.  \n\n" +
                                "Are you sure you want to change Employers?", "Unsaved Changes", MessageBoxButton.YesNo);
            if (_change == MessageBoxResult.Yes)
            {
                // OK to switch employers
                _returnValue = true;
            }
        }

        return _returnValue;
    }

一切似乎都能正常运作:

  • 用户选择更新表的雇主('KMH')。
  • 用户对表格进行了更改。
  • 用户然后选择不同的雇主('MPC')
  • 提示用户更改将丢失
  • 用户选择“否”,CanChangeEmployers返回“false”
  • SelectedEmployer不会更改(跳过if {}块)

然后回到GUI中,即使SelectedEmployer没有更改,雇主选项也会更改为用户选择的雇主('MPC')。

当我窥探ComboBox时,我发现ComboBox SelectedItem已正确设置为原始雇主('KMH'),但SelectedValue和SelectionBoxItem都设置为新雇主('MPC')。

然后我尝试将ComboBox-&gt; SelectedValue绑定到SelectedEmployer:

        <ComboBox Name="EmployerListBox"
                  IsReadOnly="True"
                  ItemsSource="{Binding EmployerCollection, UpdateSourceTrigger=PropertyChanged}"
                  SelectedValue="{Binding SelectedEmployer, UpdateSourceTrigger=PropertyChanged}" 
                  Width="150" />

GUI是相同的,显示不正确的公司。但这次Snoop显示ComboBox-&gt; SelectedValue被正确设置为原始雇主('KMH'),但SelectedItem和SelectionBoxItem都设置为新雇主('MPC')。

如何正确绑定SelectedEmployer以使GUI与所选雇主匹配?

1 个答案:

答案 0 :(得分:3)

正在发生的事情是ComboBox更改其选择,Binding更新您的viewmodel,然后viewmodel选择不更改其私有字段。但ComboBox如何知道变更被拒绝了?你不是在告诉它。

在决定保留旧值后,您可能认为SelectedEmployer.set只能为PropertyChanged提升SelectedEmployer,但我无法让它发挥作用。

执行此操作的“正确”方法是验证:让您的viewmodel实现IDataErrorInfoHere's a tutorialhere's another article。通过验证,您的IDataErrorInfo.this[propName].get方法在 ComboBox接受新选择之前被称为,并且可以选择拒绝新选择。这就是你要找的东西。如果你不想要红色轮廓错误UI的东西,你可以摆弄模板来摆脱它。

尝试处理SelectionChanged很有吸引力,但事件args没有Cancel,所以你不能把SelectedItem设置回原来的状态,再次引发SelectionChanged,所以你需要一些逻辑来阻止它无限递归。修复后,由于初始选择完成后仍然可见“闪烁”,然后再将其设置回先前的值。我个人更喜欢实施IDataErrorInfo而不是试图超越框架的温和苦差事。

更新

Here's a kinda-kludgey variant of my first idea that actually works。但是,它有同样的闪烁问题。远非理想,但它比验证工作少得多。 DispatcherPriority.ApplicationIdle是它的工作原理:它等待实际执行lambda,直到所有尘埃都从ComboBox的选择更改事件中解决了。 DispatcherPriority.Background也适合我。