创建一个通用的ObservableItem类

时间:2015-03-02 19:16:05

标签: c# wpf generics mvvm inotifypropertychanged

我想创建一个通用的ObservableItem类,我想了解如何实现它。 我希望它是通用的,以便我可以将它用于所有类型的类型(如果可能的话)。 我想创建它的原因是能够将多个控件绑定到一个数组,而不是为每个绑定创建属性。 (我想要一个双向绑定,这样当源更新时,控件将通过PropertyChanged事件通知)。 我开始创建课程,但我不知道要添加什么实现,以使其适用于每种类型的用途。

public struct ObservableItem<T> : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private T _item;
    private T Item
    {
        get {

            return _item; 
        }
        set
        {
            _item = value;
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(_item.ToString()));
        }
    }


    public static implicit operator T(ObservableItem<T> value)
    {
        return value.Item;
    }

    public static implicit operator ObservableItem<T>(T value)
    {
        var ret = new ObservableItem<T>();
        ret.Item = value;
        return ret;
    }
}

我希望该课程的用途适合所有事情:

ObservableItem<int> value1 = 5;
ObservableItem<int>[] aValue = new ObservableItem<int>[5];
aValue[0] = 4;
aValue[1] = 5;
aValue[2] = aValue[0] + aValue[1];
aValue[3] = aValue[0] * aValue[1];

ObservableItem<bool> value2;
value2 = !value2;

ObservableItem<bool>[] Channels = new ObservableItem<bool>[4];
// and more uses

Xaml绑定:

<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,0,10">
         <CheckBox IsChecked="{Binding Channels[0]}" Content="Channel 1" Style="{StaticResource Channels}"></CheckBox>
         <CheckBox IsChecked="{Binding Channels[1]}" Content="Channel 2" Style="{StaticResource Channels}"></CheckBox>
         <CheckBox IsChecked="{Binding Channels[2]}" Content="Channel 3" Style="{StaticResource Channels}"></CheckBox>
         <CheckBox IsChecked="{Binding Channels[3]}" Content="Channel 4" Style="{StaticResource Channels}"></CheckBox>
</StackPanel>

提前致谢。

1 个答案:

答案 0 :(得分:0)

我找到了解决问题的方法,所以我将其作为每个人使用的答案发布。

我没有找到一种方法来创建一个通用的ObservableItem,它允许我将它用作每个对象。像:

public ObservableItem<bool> value {get;set}

并在xaml中直接绑定到&#39;值&#39;而不是&#39; value.Item&#39;。 每当我用隐式运算符更改值时,绑定也会停止。

value = !value; //kills the binding - because the object is replaced

所以,我编写了一个ObservableItemCollection,它继承了ObservableCollection并重新实现了ObservableCollection的索引器操作符,它基于Collection,因此每个set操作都将调用PropertyChanged事件处理程序。

public class ObservableItemCollection<T> : ObservableCollection<T>
{
    private string propertyName;

    public ObservableItemCollection(string propertyName, int numberOfDefaultItemsToAdd = 0)
        : base()
    {
        this.propertyName = propertyName;
        this.AddDefaults(numberOfDefaultItemsToAdd);
    }
    public ObservableItemCollection(IEnumerable<T> collection, string propertyName, int numberOfDefaultItemsToAdd = 0)
        : base(collection)
    {
        this.propertyName = propertyName;
        this.AddDefaults(numberOfDefaultItemsToAdd);
    }
    public ObservableItemCollection(List<T> list, string propertyName, int numberOfDefaultItemsToAdd = 0)
        : base(list)
    {
        this.propertyName = propertyName;
        this.AddDefaults(numberOfDefaultItemsToAdd);
    }


    public new T this[int index]
    {
        get { return base[index]; }
        set
        {
            base[index] = value;
            // Call ObservableCollection OnPropertyChanged method.
            OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
        }
    }

    public void AddDefaults(int numberOfDefaultItemsToAdd = 1)
    {
        if (numberOfDefaultItemsToAdd < 0) throw new ArgumentOutOfRangeException("numberOfItemsToAdd must be a non-negative number");
        for(int i = 0; i < numberOfDefaultItemsToAdd; ++i)
            base.Add(default(T));
    }
}

这样我可以像任何类数组一样使用集合,并直接绑定到项目。

public ObservableItemCollection<bool> Channels { get; set; }

在xaml:

<StackPanel Orientation="Horizontal" VerticalAlignment="Top">
    <CheckBox Content="Channel 1" IsChecked="{Binding Path=Channels[0]}" Style="{StaticResource Channels}"></CheckBox>
    <CheckBox Content="Channel 2" IsChecked="{Binding Path=Channels[1]}" Style="{StaticResource Channels}"></CheckBox>
</StackPanel>

&GT;