Silverlight - содержимое кнопки не обновляется при привязке к тому же экземпляру, но измененному - PullRequest
1 голос
/ 12 октября 2009

У меня есть кнопка, и содержимое кнопки привязано к пользовательскому классу MyClass

Button button = new Button();
MyClass myClass = new MyClass() { A = 1, B = 2 };
button.Content = myClass;
stackPanel.Children.Add(button);

.... // later, on my running code

Button button = (Button)stackPanel.Children[0];
MyClass myClass = (MyClass)button.Content;
myClass.A = 421;
button.Content = myClass;

, но Button не обновляет пользовательский интерфейс для отображения нового связанного объекта, который является тем же экземпляром, но измененным.

Что это за исправление? Я не хочу устанавливать button.Content = null;, а затем button.Content = myClass. Также я не нашел никакого вспомогательного метода Refresh.

Ответы [ 2 ]

3 голосов
/ 13 октября 2009

Давайте разберемся с этим.

Что происходит

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

Простое решение, которое поможет вам и, вероятно, достаточно хорошо

Button button = new Button();
MyClass myClass = new MyClass() { A = 1, B = 2 };
button.Tag = myClass;
button.Content = myClass.ToString();
stackPanel.Children.Add(button);

...

Button button = (Button)stackPanel.Children[0];
MyClass myClass = (MyClass)button.Tag;
myClass.A = 421;
button.Content = myClass.ToString();

Свойство Tag фактически является колышком, на котором мы можем повесить связанный объект, который нам может понадобиться позже. В этом случае мы выполняем операцию ToString (). Hance Content всегда получает другую ссылку на то, что у него уже есть (по крайней мере, всегда, когда значения фактически различаются).

Более традиционное решение SL, но не обязательно желательно в этом случае

Чтобы достичь того, чего вы хотите, вам нужно сделать несколько вещей. Сначала вам нужно будет выставить свойство строкового типа в MyClass, которое содержит строку, которую вы хотите представить, давайте назовем ее DisplayValue.

public string DisplayValue { get { return String.Format("{0} {1}", A, B); } }

Теперь вам нужно каким-то образом привязать результат этого к кнопке, чтобы она могла отображать значение. Для начала следует назначить экземпляр MyClass объекту DataContext вместо Tag. Однако Button не имеет свойства Text, где в других случаях вы бы связывали DisplayProperty. Следовательно, вам нужно добавить TextBlock в качестве содержимого кнопки и связать ее Text свойство: -

Button button = new Button();
TextBlock tb = new TextBlock();
tb.SetBinding(TextBlock.TextProperty, new Binding("DisplayValue"));
button.Content = tb;
button.DataContext = myClass;   

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

 public MyClass : INotifyChanged
 {
   // ... the rest of you code
   public event PropertyChangedEventHandler PropertyChanged;
 }

Затем вам нужно вызывать событие всякий раз, когда свойство изменяется, типичный пример: -

 private int _A
 public int A
 {
    get { return _A; }
    set
    {
      _A = value;
      if (this.PropertyChanged != null)
        this.PropertyChanged(this, new PropertyChangedEventArgs("A"));
    }
 }

Тем не менее этот типичный пример не помогает. В вашем случае вы привязались к DisplayValue, и поскольку значение A влияет на его значение, ваш класс также должен уведомить DisplayValue об изменении: -

      if (this.PropertyChanged != null)
      {
        this.PropertyChanged(this, new PropertyChangedEventArgs("A"));
        this.PropertyChanged(this, new PropertyChangedEventArgs("DisplayValue"));
      }

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

Так почему же это не желательно? На самом деле это зависит от того, что представляет ваш реальный класс, но на самом деле DisplayValue определяет, как должно отображаться состояние объектов на экране. Однако действительно ли эта ответственность ложится на класс или это не ответственность за код представления, как правило, последний является верным, и DisplayValue, как правило, не очень хорошая идея (и это причина, по которой немногие классы действительно беспокоятся о переопределении ToString) .

1 голос
/ 12 октября 2009

MyClass реализует INotifyPropertyChanged. Это стандартный способ распространения изменений в пользовательском интерфейсе.

Просто реализуйте интерфейс INotifyPropertyChanged, затем в Настройщике свойств для A и B создайте событие. Это должно привести к тому, что кнопка обновит свой контент.

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