为什么 ComboB 需要 SelectionChanged 事件?您可以将所选项目直接绑定到 VM 上的属性中。
我之前解决这个问题的方法是将 ComboA 的选定项绑定到 VM 中。在该属性的设置器中,我重新计算 ComboB 的可用项并将它们分配给 VM 上的另一个属性,并且 ComboB 的 ItemsSource 绑定到此属性。当然,该属性会通知(使用 INotifyPropertyChanged),但无需执行任何其他操作,我的 ComboB 没有 SelectionChanged 事件。通过使用这种方法,我也不需要 ComboA 上的 SelectionChanged,它使视图的代码保持良好和稀疏 - 一切都在 VM 中处理,常规数据绑定负责其余部分。
编辑:
这是从属性设置器中调整所需列表的示例:
public class MyViewModel : INotifyPropertyChanged
{
//ItemsSource of ComboA is bound to this list
public List<SomeObject> ComboAList
{
get { return _comboAList; }
set { _comboAList = value; }
}
//ItemsSource of ComboB is bound to this list
public List<SomeObject> ComboBList
{
get { return _comboBList; }
set
{
_comboBList = value;
OnPropertyChanged("ComboBList");
}
}
//ItemsSource of the dataGrid is bound to this list
public List<SomeObject> DataGridList
{
get { return _datagridList; }
set
{
_datagridList = value;
OnPropertyChanged("DataGridList");
}
}
//SelectedItem of ComboA is bound to this property
public SomeObject FirstSelectedItem
{
get { return _firstSelectedItem; }
set
{
_firstSelectedItem = value;
RefreshListForComboB();
}
}
//SelectedItem of ComboB is bound to this property
public SomeObject SecondSelectedItem
{
get { return _secondSelectedItem; }
set
{
_secondSelectedItem = value;
RefreshListForDataGrid();
}
}
private void RefreshListForComboB()
{
//do whatever is necessary to filter or create a list for comboB
ComboBList = doSomethingThatReturnsAListForComboB();
}
private void RefreshListForDataGrid()
{
//do whatever is necessary to filter or create the list for the DataGrid
DataGridList = doSomethingThatReturnsAListForDataGrid();
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private List<SomeObject> _comboAList, _comboBList, _datagridList;
private SomeObject _firstSelectedItem, _secondSelectedItem;
}
这是一种稍微不同的方法,在 VM 上使用 PropertyChange 事件处理程序,这只是更改列表更新发生的位置。这可以说是比第一个示例更好的方法,因为这意味着属性设置器没有副作用:
public class MyViewModel : INotifyPropertyChanged
{
public MyViewModel()
{
this.PropertyChanged += new PropertyChangedEventHandler(MyViewModel_PropertyChanged);
}
private void MyViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case "FirstSelectedItem":
RefreshListForComboB();
break;
case "SecondSelectedItem":
RefreshListForDataGrid();
break;
}
}
//ItemsSource of ComboA is bound to this list
public List<SomeObject> ComboAList
{
get { return _comboAList; }
set { _comboAList = value; }
}
//ItemsSource of ComboB is bound to this list
public List<SomeObject> ComboBList
{
get { return _comboBList; }
set
{
_comboBList = value;
OnPropertyChanged("ComboBList");
}
}
//ItemsSource of the dataGrid is bound to this list
public List<SomeObject> DataGridList
{
get { return _datagridList; }
set
{
_datagridList = value;
OnPropertyChanged("DataGridList");
}
}
//SelectedItem of ComboA is bound to this property
public SomeObject FirstSelectedItem
{
get { return _firstSelectedItem; }
set
{
_firstSelectedItem = value;
OnPropertyChanged("FirstSelectedItem");
}
}
//SelectedItem of ComboB is bound to this property
public SomeObject SecondSelectedItem
{
get { return _secondSelectedItem; }
set
{
_secondSelectedItem = value;
OnPropertyChanged("SecondSelectedItem");
}
}
private void RefreshListForComboB()
{
//do whatever is necessary to filter or create a list for comboB
ComboBList = doSomethingThatReturnsAListForComboB();
}
private void RefreshListForDataGrid()
{
//do whatever is necessary to filter or create the list for the DataGrid
DataGridList = doSomethingThatReturnsAListForDataGrid();
}
protected void OnPropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
private List<SomeObject> _comboAList, _comboBList, _datagridList;
private SomeObject _firstSelectedItem, _secondSelectedItem;
}