簡體   English   中英

存儲其父 ObservableCollection 的通用繼承類

[英]Generic-inherited classes storing their parent ObservableCollection

我有幾個 collections,每個特定的 class。我需要每個實例(模型)存儲其父集合(以便能夠通過數據驗證訪問其他實例)。 試圖找到一些聰明的解決方案 - 開始懷疑是否有這樣的。

到目前為止,我想到了以下內容。

通用基類:

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

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

個別類(模型):

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

自定義 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) 
    {

    }

}

用法:

CustomObservableCollection<Model1> Model1Collection = new (listOfModel1instances);

我也一直在嘗試使用接口,但沒有成功。

由於集合中的每個項目都需要知道其父集合,因此解決此目標的一種方法是定義一個類似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
            }
        }
    }
} 

集合處理自己的CollectionChanged通知,將自己設置為添加到其中的任何項目的Source 這解決了存儲其父 ObservableCollection的主要問題——您可以使用它進行驗證,但您認為合適。


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

測試

這是我為測試此答案而編寫的快速控制台代碼。

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