简体   繁体   English

存储其父 ObservableCollection 的通用继承类

[英]Generic-inherited classes storing their parent ObservableCollection

I have several collections, each of specific class. I need that every instance (model) store its parent collection (to be able to reach other instances because of data validation).我有几个 collections,每个特定的 class。我需要每个实例(模型)存储其父集合(以便能够通过数据验证访问其他实例)。 Trying to find some smart solution - starting to doubt if there is such.试图找到一些聪明的解决方案 - 开始怀疑是否有这样的。

So far I came up with following.到目前为止,我想到了以下内容。

Generic base-class:通用基类:

public class ModelBase<T> : ObservableObject, IDataErrorInfo
{
    public CustomObservableCollection<T> ParentCollection;

    public int Id { get; set; }  // some generic prop
}

Individual classes (models):个别类(模型):

public class Model1: ModelBase<Model1>
{
    public string Name { get; set; } // Some specific prop

    // Data Error validation here, e.g. check of uniqueness
    if (ParentCollection?.Where(c => c.Id != Id).Any(c => c.Name == Name) == true)
    {
    }

}

public class Model2: ModelBase<Model2>
{}

Custom ObservableCollection:自定义 ObservableCollection:

public class CustomObservableCollection<T> : ObservableCollection<T> where T : ModelBase<T>
{
    public CustomObservableCollection() : base() { }

    public CustomObservableCollection(List<T> list)
            : base(list)
    {
        foreach (T item in list)
        {
            item.ParentCollection = this;
        }
    }

    public void AddEdit(T item)
    {
        item.ParentCollection = this;

        base.Add(item);
    }

    protected override void InsertItem(int index, T item)
    {
        base.InsertItem(index, item);

        item.ParentCollection = this;

        // Initialize values
    }

    // Generic method - I would like to call this directly from command handler regardless of type T
    public void MoveItemUp(object parameter) 
    {

    }

}

Usage:用法:

CustomObservableCollection<Model1> Model1Collection = new (listOfModel1instances);

I've been also trying to use Interfaces, but without success.我也一直在尝试使用接口,但没有成功。

Since each item in your collection needs to be aware of its parent collection, one way to solve this objective is to define an interface like ISourceAware and constrain CustomObservableCollection<T> to accept only items that implement it by adding where T: ISourceAware to its declaration.由于集合中的每个项目都需要知道其父集合,因此解决此目标的一种方法是定义一个类似ISourceAware的接口,并通过在其声明中添加where T: ISourceAware来约束CustomObservableCollection<T>仅接受实现它的项目.

public interface ISourceAware
{
    ICollection Source { get; set; }
}
public class CustomObservableCollection<T> : ObservableCollection<T> where T: ISourceAware
{
    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        base.OnCollectionChanged(e);
        if(e.Action.Equals(NotifyCollectionChangedAction.Add)) 
        {
            foreach (ISourceAware iitem in e.NewItems)
            {
                iitem.Source = this;
#if DEBUG
                var item = (Item)iitem;
                // Try a loopback test
                Console.WriteLine(
                    $"Index of {item.Description} is {item.ParentCollection.IndexOf(item)}");
#endif
            }
        }
    }
} 

The collection handles its own CollectionChanged notification to set itself as the Source of any item added to it.集合处理自己的CollectionChanged通知,将自己设置为添加到其中的任何项目的Source This addresses the primary issue of storing their parent ObservableCollection - you can use it for validation however you see fit.这解决了存储其父 ObservableCollection的主要问题——您可以使用它进行验证,但您认为合适。


A minimal example of a class that implements ISourceAware :实现ISourceAware的 class 的最小示例:

public class Item : ISourceAware
{
    public string Description { get; set; } = string.Empty;
    public ICollection Source { get; set; }
    public CustomObservableCollection<Item> ParentCollection =>
        (CustomObservableCollection<Item>)Source;
}

Test测试

Here's the quick console code I wrote to test this answer.这是我为测试此答案而编写的快速控制台代码。

internal class Program
{
    static void Main(string[] args)
    {
        Console.Title = "Test ISourceAware";
        var collection = new CustomObservableCollection<Item>();

        collection.Add(new Item { Description = "Item 1" });
        collection.Add(new Item { Description = "Item 2" });

        Console.ReadKey();
    }
}

控制台输出

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM