如何检查模型列表中的重复条目?

时间:2017-10-26 13:52:50

标签: c# wpf mvvm

我在ListViewlike this)中有一个由EditableTextblock组成的DataTemplate的MVVM应用。

这是我的模特:

public class MyModel
{
    private string _data;
    public string Data
    {
        get { return _data; }
        set { _data = value; }
    }
}

我的viewmodel公开ObservableCollection MyModel

public class MyViewModel
{
    [...]
    public ObservableCollection<Mymodel> models = new ObservableCollection<MyModel>();
}

并且在视图中绑定到ListView

<ListView ItemsSource={Binding models}>
    <!-- code removed for more visibility -->
    <DataTemplate>
         <controls:EditableTextblock Text="{Binding Data, Mode=TwoWay}" />
    </DataTemplate>
    <!-- ... -->
</ListView>

您是否有任何线索,当我在列表中的项目中更新数据成员的值时,会检查集合中是否已存在值?

例如,如果我将字段更新为&#34;值1&#34;,它会检查模型集合中是否存在已具有此值的成员数据。

如果它找到一个,它会增加例如&#34; 0&#34;在成员数据的末尾。

2 个答案:

答案 0 :(得分:1)

对于这样的事情,我通常将我的模型包装在他们自己的视图模型类中,并在那里添加验证。包装器将原始模型的实例包装起来,再加上对父视图模型的引用,以便它可以检查重复项或对父项执行其他操作。

如果您使用某种消息系统(如MVVMLight的Messenger类来在视图模型之间进行通信),也可以在不引用父级的情况下完成验证。

我用这种方式包装它们的主要原因是因为我喜欢保持模型“纯粹”,而不需要任何更改通知,WPF或业务逻辑,超出了域的直接要求。这允许我将模型保持为简单的数据类,并将任何业务或视图特定的逻辑移动到更合适的位置。

您现有的类(注意,我将集合更改为包装类):

public class MyViewModel : BaseViewModel //whatever base class you use to notify of property changes.
{
    [...]
    public ObservableCollection<MyModelVm> models = new ObservableCollection<MyModelVm>();
}

public class MyModel
{
    private string _data;
    public string Data
    {
        get { return _data; }
        set { _data = value; }
    }
}

新的包装器视图模型:

public class MyModelVm : BaseViewModel //whatever base class you use to notify of property changes.
{
    public MyModelVm(MyModel model, MyViewModel parentViewModel)
    {
        Model = model;
        ParentViewModel = parentViewModel;
    }

    public MyModel Model { get; }
    public MyViewModel ParentViewModel { get; }

    public string Data
    {
        get { return Model.Data; }
        set
        {
            if (ParentViewModel.models.Any(x => x != this && x.Data == this.Data))
            {
                //Duplicate entered
            }
            else
            {
                //Not a duplicate, go ahead and allow the change.
                Model.Data = value;
                //don't forget to notify of property change!
            }
        }
    }
}

答案 1 :(得分:1)

如果MyModel类实现INotifyPropertyChanged并在设置PropertyChanged属性时引发Data事件,则可以在视图模型中处理:

public class MyViewModel
{
    public ObservableCollection<MyModel> models = new ObservableCollection<MyModel>();

    public MyViewModel()
    {
        models.CollectionChanged += Models_CollectionChanged;
    }

    private void Models_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        if (e.NewItems != null)
        {
            foreach (object model in e.NewItems)
            {
                (model as INotifyPropertyChanged).PropertyChanged
                    += new PropertyChangedEventHandler(Model_PropertyChanged);
            }
        }

        if (e.OldItems != null)
        {
            foreach (object model in e.OldItems)
            {
                (model as INotifyPropertyChanged).PropertyChanged
                    -= new PropertyChangedEventHandler(Model_PropertyChanged);
            }
        }
    }

    private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        MyModel updatedModel = sender as MyModel;
        MyModel duplicate = models.FirstOrDefault(x => x != updatedModel && x.Data == updatedModel.Data);
        if(duplicate != null)
        {
            updatedModel.Data += "0";
        }
    }
}
public class MyModel : INotifyPropertyChanged
{
    private string _data;
    public string Data
    {
        get { return _data; }
        set { _data = value; NotifyPropertyChanged(); }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}