我有一个雇主组合框。选择雇主后,将使用雇主特定数据填充表格:
<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;
}
一切似乎都能正常运作:
然后回到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与所选雇主匹配?
答案 0 :(得分:3)
正在发生的事情是ComboBox更改其选择,Binding更新您的viewmodel,然后viewmodel选择不更改其私有字段。但ComboBox如何知道变更被拒绝了?你不是在告诉它。
在决定保留旧值后,您可能认为SelectedEmployer.set
只能为PropertyChanged
提升SelectedEmployer
,但我无法让它发挥作用。
执行此操作的“正确”方法是验证:让您的viewmodel实现IDataErrorInfo。 Here's a tutorial和here'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
也适合我。