Уведомление об изменении свойства в словаре - PullRequest
3 голосов
/ 11 февраля 2011

У меня есть форма 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 иногда меняется, и после этого я хочу уведомить пользовательский интерфейс об изменении свойства.

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 ]

12 голосов
/ 11 февраля 2011

Dr.WPF создал ObservableDictionary по этой ссылке: http://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);
    }
}
4 голосов
/ 07 февраля 2014

Вы можете просто создать класс, который реализует интерфейс INotifyPropertyChanged, обернуть ваше значение этим классом и использовать его в словаре.У меня была похожая проблема, и я сделал следующее:

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>

После этого, если вы измените значения в словаре, вы увидите изменения в интерфейсе пользователя.

2 голосов
/ 11 февраля 2011

Вам нужно иметь четкое представление о том, что вы пытаетесь выполнить, прежде чем приступить к реализации уведомления об изменениях.Если вы хотите, чтобы пользовательский интерфейс обновлялся при изменении объекта, сохраненного в словаре с данным ключом, это одно.Если вы хотите, чтобы пользовательский интерфейс обновлялся при изменении свойства объекта, сохраненного в словаре, это совсем другое дело.

Другими словами, если вы хотите, чтобы пользовательский интерфейс обновлялся при Reservation.Name изменений, вам нужен объект Reservation для уведомления об изменениях.Если вы хотите, чтобы пользовательский интерфейс обновлялся, когда для Seat[2B] установлено другое значение Reservation, то словарь должен будет выполнить уведомление об изменении.

1 голос
/ 11 февраля 2011

Вы всегда можете извлечь из словаря (или 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, и прикрепите обработчик к каждому новому создаваемому или полученному элементу, который будет отвечать на NotifyPropertyChanged KVP и вызовет NotifyValueChanged вашего родительского класса.

1 голос
/ 11 февраля 2011

Один из способов обойти это, вероятно, заключался бы в инкапсуляции словаря, тогда вы можете реализовать уведомляющие интерфейсы и контролировать доступ к словарю, то есть, если кто-то использует скобки для установки значения, вы можете установить значение внутреннего словаря.и поднять уведомление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...