2015-03-02 64 views
0

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

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

'PropertyChanged'必须通过物业呐,E。 – SLaks 2015-03-02 19:17:44

+0

由于SLak错过了5分钟的编辑窗口:必须通过属性*名称*传递'PropertyChanged'。 – 2015-03-02 19:27:17

+0

'if(_item == null)_item = default(T);'行没有意义。如果'T'是一个值类型,那么'_item == null'将是错误的。如果'T'是一个引用类型,那么'default(T)'将是'null'。 – juharr 2015-03-02 19:32:23

回答

0

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

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

public ObservableItem<bool> value {get;set} 

而在XAML直接绑定到 '值',而不是 'value.Item'。 此外,无论何时我会用隐式运算符更改值,绑定都会停止。

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

所以,我写了继承的ObservableCollection并重新实现的ObservableCollection的基地集合的索引操作,使每一套操作将调用PropertyChanged事件处理程序的ObservableItemCollection。

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> 

>