通知属性更改字典

时间:2011-02-11 01:22:49

标签: c# wpf data-binding

我有一个WPF / XAML表单数据绑定到字典中的属性,类似于:

<TextBox Text="{Binding Path=Seat[2B].Name}">

Seat在飞机对象上显示为属性IDictionary<String, Reservation>

class airplane
{
    private IDictionary<String, Reservation> seats;
    public IDictionary<String, Reservation> Seat
    {
        get { return seats; }
        // set is not allowed
    }
}

在我的窗口代码中,有时会更改座位2B的值,之后,我想通知UI该属性已更改。

class MyWindow : Window
{
    private void AddReservation_Click(object sender, EventArgs e)
    {
        airplane.Seat["2B"] = new Reservation();
        // I want to override the assignment operator (=)
        // of the Seat-dictionary, so that the airplane will call OnNotifyPropertyChanged.
    }
}

我看过字典是否为IObservable,以便我可以观察到它的变化,但似乎不是。

有没有什么好办法可以“抓住”飞机课程中字典的更改,以便我可以NotifyPropertyChanged

5 个答案:

答案 0 :(得分:12)

博士。 WPF在此链接上创建了ObservableDictionaryhttp://drwpf.com/blog/2007/09/16/can-i-bind-my-itemscontrol-to-a-dictionary/

更新: WPF博士在以下链接中发表的评论说他已经自行解决了这个问题,因此不再需要进行以下更改

此外,还在此链接添加了http://10rem.net/blog/2010/03/08/binding-to-a-dictionary-in-wpf-and-silverlight

小改变是

// old version
public TValue this[TKey key]
{
    get { return (TValue)_keyedEntryCollection[key].Value; }
    set { DoSetEntry(key, value);}
}

// new version
public TValue this[TKey key]
{
    get { return (TValue)_keyedEntryCollection[key].Value; }
    set
    {
        DoSetEntry(key, value);
        OnPropertyChanged(Binding.IndexerName);
    }
}

答案 1 :(得分:4)

您可以创建一个实现INotifyPropertyChanged接口的类,通过此类包装您的值并在Dictionary中使用它。我遇到了类似的问题并做了下一步:

class Parameter : INotifyPropertyChanged //wrapper
{
    private string _Value;
    public string Value //real value
    {
        get { return _Value; }
        set { _Value = value; RaisePropertyChanged("Value"); } 
    }

    public Parameter(string value)
    {
        Value = value;
    }

    public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
public class ViewModel
{
    public Dictionary<string, Parameter> Parameters
}
<ItemsControl ItemsSource="{Binding Path=Parameters, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" Margin="3" >
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Grid>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Label Grid.Column="0" Content="{Binding Path=Key}" Margin="3" />
                <TextBox Grid.Column="1" Text="{Binding Path=Value.Value, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" IsReadOnly="True" Margin="3" />
            </Grid>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

之后,如果更改字典中的值,您将看到UI中的更改。

答案 2 :(得分:2)

在开始实施变更通知之前,您需要清楚了解自己要完成的工作。如果您希望在存储在具有给定键的字典中的对象发生更改时更新UI,则这是一回事。如果您希望在存储在字典中的对象的属性发生更改时更新UI,则完全是另一回事。

换句话说,如果您希望在Reservation.Name更改时更新UI,则需要Reservation对象来执行更改通知。如果您希望在Seat[2B]设置为其他Reservation时更新用户界面,则字典需要执行更改通知。

答案 3 :(得分:1)

解决此问题的一种方法可能是封装字典,然后您可以实现通知接口并控制对字典的访问,即如果有人使用括号设置值,您可以设置内部字典的值并提出通知。

答案 4 :(得分:1)

您总是可以从Dictionary(或IDictionary)派生出来生成ObservableDictionary:

public class ObservableDictionary<TKey, TVal>:IDictionary<TKey, TVal>, IObservable
{
   private Dictionary<TKey, TVal> _data;

   //Implement IDictionary, using _data for storage and raising NotifyPropertyChanged
}

您可能遇到的最大问题是您将无法直接检测到值的更改;仅添加和删除KVP。为此,将_data更改为List<ObservableKeyValuePair>,同时在那里实现IObservable,并将处理程序附加到您创建或接收的每个新元素,这些元素将响应KVP的NotifyPropertyChanged并引发父类的NotifyValueChanged。