C # привязка данных переменных класса - PullRequest
1 голос
/ 01 июля 2010

Я действительно влюбляюсь в всю схему привязки данных .Net ... но, видимо, есть еще несколько ошибок.Допустим, у моего класса есть переменная-член типа double с именем Susan.Что ж, похоже, нет непосредственного способа привязать Susan к текстовому полю SusanText, потому что привязка выглядит примерно так

SusanText.DataBindings.Add("Text",datasource,"Property")

А Susan не являетсяимущество.Так что я могу сделать Susan публичной собственностью, но это вроде как воняет ... что если я захочу скрыть Susan?(Полагаю, я мог бы сделать Susan публичным свойством частного экземпляра некоторого внутреннего класса ... но для небольшого двойника это большая работа.) Однако у меня возникла более серьезная проблема, поэтому радиВ качестве аргумента давайте продолжим и сделаем следующее:

private double Susan_;
public double Susan{ get; set;}
...
SusanText.DataBindings.Add("Text",this,"Susan")

Тогда все изначально кажется работающим, как и ожидалось.Если я изменяю SusanText, Susan изменяется соответственно.Однако проблема возникает, когда я изменяю Susan напрямую.Я бы хотел, чтобы SusanText автоматически обновлялся.Поэтому я подозреваю, что мне нужно сделать Susan подклассом double, который реализует некоторый интерфейс IBindable, так что если Susan связан с данными SusanText, что соответствующие События зарегистрированы, и Susan уведомит других, если она

Какой самый простой способ заставить Susan делать то, что я от нее хочу?

Спасибо!

Ответы [ 2 ]

3 голосов
/ 01 июля 2010

DataBinding ожидает, что класс, к которому он привязан, должен поднять INotifyPropertyChanged, чтобы указать, что значение было изменено и его необходимо перечитать; к сожалению, реализация этого все еще требует некоторого ручного кодирования (или что-то вроде PostSharp для IL-weave необходимого кода).

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

Другим недостатком DataBinding является то, что он не учитывает многопоточность. Если фоновый поток изменяет значение базы данных, тогда привязка данных попытается выполнить перекрестный вызов для обновления пользовательского интерфейса - что плохо. Лучший обходной путь, который я нашел, - позволить связываемым классам содержать экземпляр их пользовательского интерфейса Synchronization Context, что позволит вам гарантировать, что обновления пользовательского интерфейса будут вызываться в потоке пользовательского интерфейса.

using System.ComponentModel;

namespace MyWebGrocer.Uma.UI
{
  public class BoundClass : INotifyPropertyChanged
  {
    private string _Name;

    private int _Age;

    public event PropertyChangedEventHandler PropertyChanged;

    public string Name
    {
      get
      {
        return _Name;
      }
      set
      {
        _Name = value;
        OnPropertyChanged("Name");
      }
    }

    public int Age
    {
      get
      {
        return _Age;
      }
      set
      {
        _Age = value;
        OnPropertyChanged("Age");
      }
    }

    protected void OnPropertyChanged(string propertyName)
    {
      var propertyChanged = PropertyChanged;
      if (propertyChanged != null)
      {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
      }
    }
  }
}

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

0 голосов
/ 01 июля 2010

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

Вот самый простой способ:

namespace MyProject
{
    public sealed class ViewModel : DependencyObject //handles all databinding voodoo
    {
        public string Susan
        {
            get { return (string)GetValue(SusanProperty); }
            set { SetValue(SusanProperty, value); }
        }

        public static readonly DependencyProperty 
            SusanProperty = DependencyProperty.Register
                ("Susan", typeof(string), 
                typeof(ViewModel));
    }
}

и в xaml:

<Window.DataContext>
  <ViewModel xmlns="clr-namespace:MyProject" />
</Window.DataContext>
<Grid>
  <TextBox Text="{Binding Susan}" />
</Grid>
...