我有一个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
。此外,我没有找到任何助手刷新方法。
答案 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引发事件。这应该会使按钮刷新其内容。