Seatвыставляется как объект IDictionaryна объекте самолета.class airplane{ private IDictionary<" />

Уведомление об изменении свойства в словаре

19143 просмотра

5 ответа

У меня есть форма 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.

Автор: abelenky Источник Размещён: 12.11.2019 09:24

Ответы (5)


13 плюса

Решение

Доктор 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);
    }
}
Автор: Fredrik Hedblad Размещён: 11.02.2011 01:49

4 плюса

Вы можете просто создать класс, который реализует интерфейс 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>

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

Автор: Paval Размещён: 07.02.2014 05:14

2 плюса

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

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

Автор: Robert Rossney Размещён: 11.02.2011 01:51

1 плюс

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

Автор: H.B. Размещён: 11.02.2011 01:30

1 плюс

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

Автор: KeithS Размещён: 11.02.2011 01:44
32x32