Привязка данных к члену класса - PullRequest
1 голос
/ 16 июня 2010

Мне нужна помощь по WPF и привязке данных.

Допустим, у меня есть ClassA с членом ClassB.ClassB снова имеет член, может быть, int:

ClassB
{
  public int MemberOfB { get; set; }
}

ClassA
{
    private ClassB _theB;
    public ClassB MemberOfA
    {
        get {return _theB;}
        set
        {
            _theB = value;

            // Need to do something here...
        }
    }
}

Когда у меня есть привязка данных в XAML, например:

<TextBox Text="{Binding Path=MemberOfA.MemberOfB}"/>

Где Datacontext из Textbox является объектом типа ClassA.

Как видите, мне нужно выполнить некоторые вычисления в установщике MemberOfA в ClassA.Но с привязкой данных выше, этот установщик, конечно, никогда не вызывается, потому что он привязывается к члену ClassB.

Итак, как я могу получить информацию, если изменяется MemberOfA (когда я набираю что-то в текстовое поле)?Есть ли лучшие практики?(Не проверял код в Visual Studio, поэтому могут быть некоторые синтаксические ошибки).

Спасибо, Уолтер

Ответы [ 2 ]

2 голосов
/ 16 июня 2010

Лучший способ справиться с этим, вероятно, состоит в том, чтобы B реализовал INotifyPropertyChanged.Когда A получает новый экземпляр B, подключите его к событию PropertyChanged (и отсоедините от события старого B, если это необходимо).

public B MemberOfA {
    get { return _b; }
    set {

        if (_b != null) { _b.PropertyChanged -= B_PropertyChanged; }

        _b = value;

        if (_b != null) { _b.PropertyChanged += B_PropertyChanged; }

        DoWhatever(_b);

    }
}

private void B_PropertyChanged(object sender, PropertyChangedEventArgs e) {
    DoWhatever((B)sender);
}
0 голосов
/ 16 июня 2010

Фундаментальная проблема

По моему мнению, все сторонние поставщики должны реализовать по крайней мере один из стандартных механизмов уведомления NET Framework, а именно:

  • Исходный шаблон событий XyzChanged
  • INotifyPropertyChanged
  • INotifyCollectionChanged
  • OnDependencyPropertyChanged

Все они полностью поддерживаются WPF, поэтому, если ваш поставщик реализует какой-либо из них, вы сможете просто поместить их объекты в ваше приложение WPF и перейти.

К сожалению, вы найдете много сторонних библиотек, которые не реализуют ни один из этих механизмов: вместо этого они реализуют свои собственные пользовательские уведомления об изменениях или даже вообще не используют их!

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

1. Заворачивать объекты сторонних производителей в модели оберток

Вы можете создать объект «модель-обертка», который будет параллелен каждому объекту-модели третьей стороны, который не реализует стандартные уведомления. Выставьте все свойства и методы сторонних разработчиков как свои собственные (да, это много кода). Зарегистрируйтесь с помощью механизма нестандартных уведомлений стороннего объекта и отправляйте стандартные уведомления с помощью INotifyPropertyChanged. Это решение является трудоемким и может быть головной болью при техническом обслуживании, но оно работает хорошо и во многих случаях является хорошим способом исправить плохую ситуацию.

Многие люди называют эти модели-оболочки «моделями представления», но эта терминология приводит к путанице: «модель представления» - это, по сути, модель, которая моделирует текущее состояние пользовательского интерфейса, такое как то, что пользователь открыл прямо сейчас, какие объекты текущий фильтр поиска и т. д. Привязка данных WPF обычно привязывается к модели представления для этих типов свойств, но непосредственно к самим объектам модели для фактических данных.

Когда объекты модели не поддерживают стандартное уведомление, обычно перегружают использование объектов модели представления, чтобы представить как «реальные» свойства модели представления, так и свойства из базовых моделей. Таким образом, модель представления действует как в качестве реальной модели представления, так и в качестве модели оболочки: дополнительные свойства не имеют ничего общего с состоянием пользовательского интерфейса, но являются просто удобным способом получения надлежащего уведомления об изменениях без использования отдельной модели оболочки вокруг сломанного стороннего объекта. .

Нет ничего плохого в том, чтобы объединить вашу модель-оболочку и вашу модель представления в один объект, но это путает терминологию. Для многих я думаю, что «модель представления» стала синонимом «модели оболочки», и я считаю, что это позор. Если модель оболочки хранится отдельно от модели представления, вы получаете более чистый интерфейс в своем XAML и можете легче адаптироваться после того, как поставщик исправит свое уведомление об изменении.

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

2. Заменить DataContext в уведомлении

Вы можете просто задействовать сторонний механизм уведомления об изменениях, и каждый раз, когда сообщается об обновлении, просто очищайте соответствующий DataContext (установите его на ноль) и устанавливайте его снова. Это приведет к переоценке всех привязок данных WPF.

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

Это решение может быть единственным решением, если механизм уведомления об изменениях стороннего производителя нарушен или несовместим.Это также, как правило, самое простое «быстрое и грязное» решение, если вам нужно получить что-то полезное за дверь СЕГОДНЯ.

3.Обтекание с использованием TransparentProxy / RealProxy

Если ваша сторонняя библиотека включает в себя разумный и непротиворечивый, но нестандартный механизм уведомления об изменениях, у вас есть другая альтернатива: вы можете реализовать обобщенное сопоставление между сторонним механизмом и стандартным INotifyPropertyChangedмеханизм с использованием механизма TransparentProxy / RealProxy NET Framework.

Для этого:

  1. Предоставьте интерфейс INotifyPropertyChanged на TransparentProxy и на вашем дескрипторе RealProxy add_PropertyChangedи remove_PropertyChanged путем регистрации в системе уведомлений о событиях третьей стороны
  2. Когда RealProxy получает свойство получить свойство, выполните любую стороннюю регистрацию, необходимую для уведомления об изменении этого конкретного свойства (если это еще не сделано), прежде чем возвращатьсвойство
  3. Автоматически преобразовывать каждый объект, возвращаемый получателями стороннего свойства, в TransparentProxy того же объекта.

Теперь вы можете привязать свой DataContext к изначально сконструированному TransparentProxy и с тех пор притворяться, что сторонняя библиотека использует стандартный механизм уведомления об изменениях и полностью совместима с WPF.

Решение TransparentProxy / RealProxyмного работы по настройке, специфичной для механизма уведомлений сторонней библиотеки, но как только он заработает, вам не нужно беспокоиться о потере несинхронизированного пользовательского интерфейса или при потере пользовательского интерфейса во время обновлений.

4.Используйте таймер

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

Ваш таймер, вероятно, будет сканировать стороннюю версиюобъект для соответствующих изменений от значений во время последнего сканирования.Если они найдены, он использует один из предыдущих методов для предоставления стандартного уведомления об изменениях.Другими словами, он будет сигнализировать оберточную модель или RealProxy об изменении или очистит / установит DataContext.

Самое простое из возможных решений таймера просто периодически устанавливает значение DataContext равным нулю, а затем снова устанавливает его без проверкиизменения.

5.Поощряйте вашу стороннюю организацию внедрить один из стандартных механизмов

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

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

Печально то, что на данный момент Microsoft является худшим виновником из всех: ни LINQ to SQL, ни LINQ to Entities не реализуют стандартизменить уведомления на своих объектах!Я думаю, что это очень плохо, потому что люди склонны следовать примеру Microsoft.

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