Silverlight MVVM,停止SelectionChanged触发以响应ItemsSource重置

时间:2011-06-07 12:24:55

标签: silverlight-4.0 mvvm combobox inotifypropertychanged selectionchanged

我有两个组合框,A& B,每个都绑定到一个Observable Collection。每个都附有一个SelectionChanged触发器,用于在用户更改选择时捕获。触发器将选择传递给命令。

集合实现了INotifyPropertyChanged,在每个Setter中,会触发NotifyPropertyChanged事件。这需要(在MVVM方法中)通知UI(View)ComboBox的内容已经改变。

两个组合框是相互依赖的 - 更改A中的选择会导致B重新填充新项目。

现在,问题在于B的SelectionChanged触发器会响应其重新填充的集合(以及用户更改选择)而触发。由于命令中代码的复杂性,这极大地浪费了资源。

理论上我可以通过在设置B集合时不提升NotifyPropertyChanged事件来阻止这种情况(因为,查看调用堆栈,这似乎会导致SelectionChanged触发器触发),但是MVVM方法依赖于此保持用户界面刷新。

有什么建议吗?

1 个答案:

答案 0 :(得分:2)

为什么ComboB需要SelectionChanged事件?您可以直接将所选项目绑定到VM上的属性中。

我之前解决这个问题的方法是将ComboA的选定项目绑定到VM中。在该属性的setter中,我重新计算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;
}
相关问题