I hav开发者_开发技巧e a Button and the button content is binded to a custom class called 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;
but the Button does not refresh the UI to reflect the new binded object, wich is the same instance but changed.
What is the fix for this? I don't want to set the button.Content = null;
and then button.Content = myClass
. Also I didn't finded any helper Refresh method.
Lets break this down.
Whats happening
Your MyClass
will have an override on ToString
the generates a string that represents the value of the object which will be function of the properties you've assigned. When you assign the object to Content
the SL framework it calls the ToString
to get some text to display. As you have rightly discovered assigning the same
reference doesn't invoke this call again.
A simple solution that will get you going and is likely good enough
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();
The Tag
property is effectively a peg on which we can hang a related object that we may need later. In this case we are performing the ToString() operation hance Content always gets a different reference to what it already has (at least always when the values are actually different).
A more traditional SL solution but not necessarily desirable in this case
To achieve what you want you would need to do several things. First you will need to expose a property of string type on MyClass
that contains the string you want to present, lets call it DisplayValue
.
public string DisplayValue { get { return String.Format("{0} {1}", A, B); } }
Now you need to bind the result of this to the Button in some way so that it can display the value. A start would be to assign the instance of MyClass
to the DataContext
proeprty instead of Tag
. However Button
doesn't' have a Text
property where in other cases you would bind the DisplayProperty
. Hence you need to add a TextBlock
as the content of the button and bind its Text
property:-
Button button = new Button();
TextBlock tb = new TextBlock();
tb.SetBinding(TextBlock.TextProperty, new Binding("DisplayValue"));
button.Content = tb;
button.DataContext = myClass;
However in order for control to know that the bound value has been changed your MyClass
needs to implement INotifyPropertyChanged
. You add this to your class like this:-
public MyClass : INotifyChanged
{
// ... the rest of you code
public event PropertyChangedEventHandler PropertyChanged;
}
You then need to raise the event whenever a property is changed a typical example:-
private int _A
public int A
{
get { return _A; }
set
{
_A = value;
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs("A"));
}
}
Still this typical example doesn't help. In your case you've bound to DisplayValue
and since the value of A influences its value your class also needs to notify DisplayValue
changed:-
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("A"));
this.PropertyChanged(this, new PropertyChangedEventArgs("DisplayValue"));
}
As you can see its significantly more complex than the other solution yet doesn't seem to deliver any more. The key advantage is that logic in you application can now concentrate on mutating object values without having concern itself with keeping the display up-to-date, that takes care of itself. Hence it enables good separation of logical code from presentation code.
So why might this not be desirable? It depends really what your real class represents but in effect the DisplayValue
is dictating how the objects state should be represented on screen. However does this responsibility really rest with the class or is that not the responsibility of presentation code, typically the latter is true and the DisplayValue
is generally not a good idea (and is the reason why few class actually bother overriding ToString
).
Does MyClass implement INotifyPropertyChanged. That is the standard way to propogate changes to the UI.
Simply implement the INotifyPropertyChanged interface then in the Property Setter for A and B raise the Event. This should cause the button to refresh its content.
精彩评论