Связанные элементы управления WPF обновляются только при изменении значения на null

Я привязал элемент управления к свойству динамического типа, My MainWindow Class наследует от INotifyPropertyChanged, также определил метод OnPropertyChanged:

public event PropertyChangedEventHandler PropertyChanged;
    private void OnPropertyChanged(String name)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(name));
        }
    }

мой xaml выглядит так

<ListBox DataContext="{Binding ElementName=UI}" Name="EquipmentKinds" ItemsSource=" {Binding system_slots}" Grid.Row="1" Margin="10, 10, 10, 10" SelectionChanged="EquipmentKinds_SelectionChanged"/>
                        <TextBox Name="EditEquipmentKinds" Grid.Row="2" Margin="10, 10, 10, 10" Height="25" TextChanged="EditEquipmentKinds_TextChanged" />

свойство system_slots объявлено как

public dynamic system_slots
    {
        get
        {
            if (_system != null)
            {
                return _system.equipment_kinds;
            }
            else
            {
                return null;
            }
        }

        set { _system.equipment_kinds = value; OnPropertyChanged("system_slots"); OnPropertyChanged("system"); }
    }

Каждый раз, когда я менял значение system_slots, я вызывал метод OnPropertyChanged.

Когда я например добавить новый слот в system_slots, мне нужно установить для system_slots значение null, если я хочу, чтобы список обновлялся, например. мой код для этого

dynamic new_system = CreateCopyOfSystem(system);
        new_system.equipment_kinds.Add("New Slot".ToRubyString());
        system_slots = null;
        system_slots = new_system.equipment_kinds;
        OnPropertyChanged("system");
        OnPropertyChanged("system_slots");

Если я не установил для system_slots значение null, он не обновляется, любая помощь, так как я новичок в WPF ??

EDIT: What i tried is to use ObservableCollection, DependencyProperties, and I found here an example where someone Get Binding and trigger it manually but still it didn't help.

Все динамические типы - это рубиновые объекты из библиотеки IronRuby (имеется в виду массивы и хэши для коллекций пользовательских классов). Если я понимаю WPF, элемент управления должен обновляться, если он привязан к Object, и я вызываю OnPropertyChange (Object_name), но он не обновляется, пока я не изменю Object на null. Задница За ошибку с observableCollection было что-то с Coversion от RubyArray до ObservableCollection.


person user3926274    schedule 10.08.2014    source источник
comment
Он работает в небольшом образце, который я пробовал. Можете ли вы разместить код там, где он воспроизводится?   -  person Rohit Vats    schedule 10.08.2014
comment
Странно для меня не работает я использую VS Express 2010 и Net 4.0   -  person user3926274    schedule 10.08.2014
comment
Не знаю насчет ToRubyString(). В примере я пробовал использовать простые строковые значения, и он работает с VS2010 и .Net 4.0.   -  person Rohit Vats    schedule 10.08.2014
comment
equipment_kinds какого типа в вашей реальной реализации?   -  person Rohit Vats    schedule 10.08.2014
comment
RubyArray из библиотеки IronRuby, toRubyString преобразует строку в MutableString также из IronRuby, настоящая проблема, даже если я запускаю OnPropertyChanged в методе, он не обновляет элементы управления (это для всех элементов управления, а не только для одного. Я также искал метод, который позволяет запускать обновление элемента управления вручную, но я не нашел.   -  person user3926274    schedule 10.08.2014


Ответы (1)


Поскольку вы используете dynamic, трудно точно сказать, какие типы коллекций вы используете, но, похоже, есть одна вещь, о которой вы споткнулись.

WPF заметит событие PropertyChanged, инициированное для свойства, только если значение свойства изменилось. Для ссылочных типов «изменено» означает «не ReferenceEquals к старому значению». Возможно, вы добавили элемент в список, поэтому он больше не равен своему старому значению, но он все равно будет ReferenceEquals своему старому значению - сам список имеет тот же адрес в памяти, что и до того, как элемент был добавлен в Это.

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

Попробуйте вместо этого использовать ObservableCollection. Это вызывает события всякий раз, когда элемент добавляется, удаляется или изменяется. WPF знает об этом классе (или, скорее, об интерфейсе INotifyCollectionChanged, который он реализует), слушает его события и реагирует на них.

person Luke Woodward    schedule 10.08.2014
comment
Я пробовал использовать, но об этом не может быть и речи, поскольку в динамическом классе я использую для реализации ironruby, поэтому это другой класс ruby, который дает мне ошибки, когда я пытался его использовать. - person user3926274; 10.08.2014
comment
Я недостаточно хорошо знаю IronRuby, чтобы прокомментировать, как заставить ObservableCollections работать с ним, но, на мой взгляд, это определенно правильный путь. Также было непонятно, касается ли ваш вопрос IronRuby. Я добавил к нему метку из железного рубина. Наконец, какие ошибки вы упомянули в своем комментарии? Измените свой вопрос, включив в него то, что вы пробовали, и ошибки, которые у вас были. - person Luke Woodward; 10.08.2014
comment
@LukeWoodward - WPF will only take notice of a PropertyChanged event fired for a property if the value of the property has changed.. Это неправда. Движок привязки перехватывает только событие PropertyChanged. Если событие возникает явно, даже если значение не изменилось, пользовательский интерфейс все равно отвечает на него и обновляет соответствующие привязки. - person Rohit Vats; 10.08.2014
comment
@RohitVats: Думаю, вы обнаружите, что то, что я написал, является правдой, хотя я изо всех сил пытаюсь найти какую-либо документацию, подтверждающую это. Если вы мне не верите, запустите Visual Studio, выберите решение для быстрого тестирования и попробуйте сами. Безусловно, я только что сделал это сам и могу подтвердить то, что написал. Кроме того, если бы то, что вы написали, было правильным, здесь не было бы никаких вопросов, и исходный код спрашивающего просто работал бы. - person Luke Woodward; 11.08.2014
comment
@LukeWoodward - Вы не смогли найти никакой письменной документации, потому что не существует документа, подтверждающего ваше ложное утверждение. Просто создайте простой TextBlock и привяжите его Text к некоторому строковому свойству через конвертер. При нажатии кнопки событие изменения свойства поднять, и вы увидите, что конвертер сработал. (Пользовательский интерфейс запрашивает это, когда фактического изменения свойств не происходит). Не уверен, что заставляет вас это утверждать, хотел бы увидеть ваш образец, который заставляет вас думать, что свойство необходимо изменить. - person Rohit Vats; 11.08.2014
comment
Более того, я уже прокомментировал вопрос OP о том, что он работает в небольшой выборке (проблема где-то в его коде может быть связана с Ruby, потому что я проверяю ее с помощью обычных объектов). В любом случае, предполагая, что ваше утверждение истинно, но с этой строкой system_slots = new_system.equipment_kinds; пользователь устанавливает его для завершения новой ссылки, потому что new_system - это совершенно новый объект, поэтому ссылка будет другой. - person Rohit Vats; 11.08.2014
comment
@RohitVats: через конвертер? Вы видите OP, использующий конвертер? Если преобразователь возвращает значение, отличное от ReferenceEquals последнего возвращенного значения, то изменение будет считаться произошедшим. У меня есть тестовое решение прямо здесь. Если ваше утверждение о том, что WPF отвечает на каждое событие PropertyChanged, верно, окно сообщения «Строки изменены» должно появляться каждый раз, когда вы нажимаете «Добавить элемент». Это не. - person Luke Woodward; 11.08.2014
comment
@RohitVats: если CreateCopyOfSystem создает только неглубокую копию объекта system, тогда вполне возможно, что system_slots и new_system.equipment_kinds уже ReferenceEquals друг другу перед назначением, что, следовательно, не будет иметь никакого эффекта. Конечно, я точно не знаю, что делает CreateCopyOfSystem, так как у меня нет источника этого метода. - person Luke Woodward; 11.08.2014
comment
@LukeWoodward - Вы видите ссылку на конвертер с вопросом OP в моем комментарии? Конвертер, о котором я упоминал, не имеет отношения к вопросу OP. Поскольку вы написали ответ в общем, WPF реагирует на изменение свойства только тогда, когда изменение значения не действует для всех. Даже в вашем примере вы используете List<string>, и для этого же списка требуется CollectionChanged, с чем я тоже согласен. Но не для всех объектов. Метод Converter получает удар, что означает, что пользовательский интерфейс реагирует на событие изменения свойства, если вы не хотите покупать, что я больше не буду тянуть это обсуждение. - person Rohit Vats; 11.08.2014
comment
Of course, I don't know exactly what CreateCopyOfSystem does, as I don't have the source to this method. - Так зачем делать утверждения, не зная, что именно они делают? - person Rohit Vats; 11.08.2014