【问题标题】:How to check a duplicate entry in a list of models?如何检查模型列表中的重复条目?
【发布时间】:2017-10-26 13:52:49
【问题描述】:

我有一个 MVVM 应用程序,其 ListViewEditableTextblocks 在 DataTemplate (like this) 中组成。

这是我的模型:

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

我的视图模型暴露了ObservableCollectionMyModel

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>

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

例如,如果我将一个字段更新为“值 1”,它会检查模型集合中是否有成员 Data 已经具有该值。

如果它找到一个,它会在成员数据的末尾添加一个“0”。

【问题讨论】:

  • 顺便说一下,您在模型中所做的更改不会在视图中更新。您的 MyModel 类没有实现 INotifyPropertyChanged,但您绑定到该类的属性。
  • @dymanoid 这可能只是 OP 输入原始问题时的疏忽。

标签: c# wpf mvvm


【解决方案1】:

假设MyModel 类实现INotifyPropertyChanged 并在设置Data 属性时引发PropertyChanged 事件,您可以在视图模型中处理此问题:

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

【讨论】:

  • 我写了一个extension method,它让其他人更容易实现这种模式。
【解决方案2】:

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

如果您使用某种消息系统(例如 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!
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 2012-12-06
    • 1970-01-01
    • 1970-01-01
    • 2020-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-18
    相关资源
    最近更新 更多