Silverlight MVVM,停止SelectionChanged触发,以响应ItemsSource重置 [英] Silverlight MVVM, stop SelectionChanged triggering in response to ItemsSource reset

查看:153
本文介绍了Silverlight MVVM,停止SelectionChanged触发,以响应ItemsSource重置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I have two ComboBoxes, A & B, each bound to an Observable Collection. Each has a SelectionChanged trigger is attached which is intended to catch when the user changes a selection. The trigger passes the selection to a Command.

集合实现了INotifyPropertyChanged,在每个集合的Setter中,一个NotifyPropertyChanged事件被触发。这是需要的(在MVVM方法中)通知UI(视图)ComboBox的内容已更改。

The collections implement INotifyPropertyChanged in that, in the Setter of each, an NotifyPropertyChanged event is fired. This is needed (in the MVVM approach) to notify the UI (the View) that the ComboBox's contents have changed.

两个ComboBox是相互依赖的 - 更改A导致B被重新填充新的项目。

The two ComboBoxes are interdependent - changing the selection in A causes B to be repopulated with new items.

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

Now, the problem is that B's SelectionChanged trigger fires in response to its collection being repopulated (as well as the user changing a selection). Due to the complexity of the code in the Command this is a huge waste of resources.

我可以在理论上阻止这一点,当B的集合设置不提高NotifyPropertyChanged事件(因为,看看Call Stack,这是什么似乎导致SelectionChanged触发器触发),然而MVVM方法依赖于这保持UI更新。

I could in theory stop this by not raising the NotifyPropertyChanged event when B's collection is set (because, looking at the Call Stack, this is what seems to cause the SelectionChanged trigger to fire), however the MVVM approach depends on this to keep the UI refreshed.

任何建议?

推荐答案

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

Why does ComboB need a SelectionChanged event? You can just bind the selected item directly into a property on the VM.

我之前解决的方式是将ComboA的选定项目绑定到VM中。在该属性的设置器中,我重新计算ComboB的可用项,并将它们分配给VM上的另一个属性,并且ComboB的ItemsSource绑定到此属性。当然,该属性将通知(使用INotifyPropertyChanged),但没有其他需要做,我的ComboB没有SelectionChanged事件。通过使用这种方法,我不需要在ComboA SelectionChanged,它保持视图的代码后面漂亮和稀疏 - 一切都在VM中处理,常规数据绑定照顾其余。



The way i have tackled this previously was to bind ComboA's selected item into the VM. In the setter for that property, i recalculate the available items for ComboB and assign them to another property on the VM, and ComboB's ItemsSource is bound to this property. Of course that property will notify (using INotifyPropertyChanged), but nothing else needed to be done, my ComboB did not have a SelectionChanged event. By using this method i didn't need a SelectionChanged on ComboA either, which keeps the view's code behind nice and sparse - everything is handled in the VM and regular databinding takes care of the rest.

需要的属性设置列表:

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;
}

这里有一个稍微不同的方式来做,使用PropertyChange事件处理程序在VM上,这只是更改列表更新的位置。这可能是比第一个样本更好的方法,因为它意味着属性设置没有副作用:

And here is a slightly different way to do it, using a PropertyChange event handler on the VM, this simply changes where the list updating happens. This is arguably a better way of doing it than the first sample as it means the property setters don't have side effects:

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;
}

这篇关于Silverlight MVVM,停止SelectionChanged触发,以响应ItemsSource重置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆