Silverlight - 按钮内容在绑定到同一实例但未修改时不会刷新

时间:2009-10-12 16:53:11

标签: silverlight binding

我有一个Button,按钮内容绑定到名为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不刷新UI以反映新的绑定对象,它是相同的实例但已更改。

对此有何修复?我不想设置button.Content = null;然后设置button.Content = myClass。此外,我没有找到任何助手刷新方法。

2 个答案:

答案 0 :(得分:3)

让我们打破这个。

发生了什么

您的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()操作,内容总是获得对它已有的不同的引用(至少在值实际上不同时)。

更传统的SL解决方案,但在这种情况下不一定是理想的

要达到你想要的效果,你需要做几件事。首先,您需要在MyClass上公开包含您要呈现的字符串的字符串类型的属性,然后将其称为DisplayValue

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

现在您需要以某种方式将此结果绑定到Button,以便它可以显示值。一个开始是将MyClass的实例分配给DataContext proeprty而不是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通常不是一个好主意(并且是为什么几个类实际上打扰覆盖{{{ 1}})。

答案 1 :(得分:1)

MyClass是否实现了INotifyPropertyChanged。这是传播UI更改的标准方法。

只需实现INotifyPropertyChanged接口,然后在属性设置器中为A和B引发事件。这应该会使按钮刷新其内容。