How to cause bindings to be updated, particularly for derived values? - c#

I'm using some CLR objects that use the INotifyPropertyChanged interface and use the PropertyChanged function to update in WPF bindings.
Pretty boilerplate:
protected void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Then the property:
private double m_TotalWidgets = 0;
public double TotalWidgets
{
get { return m_TotalWidgets; }
set
{
m_TotalWidgets = value;
RaisePropertyChanged("TotalWidgets");
}
}
Is there a better way to update a derived value or even the whole class?
Say I had a calculated value:
public double ScaledWidgets
{
get
{
return TotalWidgets * CONSTANT_FACTOR;
}
}
I would have to fire ScaledWidget's PropertyChanged when TotalWidgets is updated, eg:
set
{
m_TotalWidgets = value;
RaisePropertyChanged("TotalWidgets");
RaisePropertyChanged("ScaledWidgets");
}
Is there a better way to do this? Is it possible "invalidate" the whole object, especially if there are a lot of derived values? I think it would be kind of lame to fire 100 PropertyChanged events.

You can raise the PropertyChangedEvent with the parameter string.empty or null. Then all properties of the object get "invalidated". See my post here

I don't know if there is a better way but I can suggest two things:
Create a class that encapsulates the firing of the PropertyChanged event so you don't have to write a lot of boilerplate code. You just have to declare the PropertyChanged event and use that class to invoke it.
If there are properties that are dependent from each other. Create a handler to the independent property so that every time it changes you can invoke the dependent properties. For example you can have an internal handler for TotalWidgets so that when it changes, you can change ScaledWidgets accordingly.
Why do you have to write 100 PropertyChanged events? Maybe it's not necessary and the problem is somewhere else.

Related

C# WPF Databinding an Image control to an array element [duplicate]

Can someone explain me why need to use implementation of INotifyPropertyChanged when using binding in wpf?
I can bind properties without implementation of this interface?
For example i have code
public class StudentData : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
string _firstName = null;
public string StudentFirstName
{
get
{
return _firstName;
}
set
{
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
And binding in .xaml
<TextBox Text="{Binding Path=StudentFirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1"
Grid.Column="2"
VerticalAlignment="Center" />
this code from .xaml.cs
StudentData _studentData = new StudentData { StudentFirstName = "John", StudentGradePointAverage = 3.5};
public MainWindow()
{
InitializeComponent();
this.DataContext = _studentData;
}
why we need to use INotifyPropertyChanged in this case?
It is not my code.
You need INotifyPropertyChanged if you want a wpf form to be automatically updated when a property changes through code. Also some controllers might want to know if edits have been made in order to enable/disable a save-button, for instance. You also might be displaying the same property on different views; in this case INotifyPropertyChanged helps to immediately update the other view when you edit a property.
If you think that your form behaves well without INotifyPropertyChanged, then you can drop it.
Note that binding works even without INotifyPropertyChanged. See: Why does the binding update without implementing INotifyPropertyChanged?
I would implement the properties like this. In some rare cases it can help to avoid endless circular updates. And it is more efficient by the way.
private string _firstName;
public string StudentFirstName
{
get { return _firstName; }
set
{
if (value != _firstName) {
_firstName = value;
OnPropertyChanged("StudentFirstName");
}
}
}
Starting with C#6.0 (VS 2015), you can implement OnPropertyChanged like this:
private void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
When you bind to a property of StudentData such as the StudentFirstName then the binding class tests to see if the StudentData instance provides the INotifyPropertyChanged interface. If so then it will hook into the PropertyChanged event. When the event fires and it fires because of the StudentFirstName property then it knows it needs to recover the source value again because it has changed. This is how the binding is able to monitor changes in the source and reflect them in the user interface.
If you do not provide the INotifyPropertyChanged interface then the binding has no idea when the source value changes. In which case the user interface will not update when the property is changed. You will only see the initial value that was defined when the binding was first used.
It does need to be implemented in order for binding to work but that doesn't mean you always have to do it yourself. There are other options like Castle Dynamic Proxy (which wraps your classes in a proxy and injects INPC into all virtual properties) and Fody (which adds it to the IL in a post-processing step). It's also possible to implement yourself while at the same time reducing code bloat, as demonstrated in my answer to this question.

Is there anything like, or similar to a routed version of the INPC interface?

Using RoutedEvents, you can do things such as have a single control which hosts thousands of child controls, but rather than subscribe to MouseDown on each child, you set a handler on the root control and inspect the 'sender' property to find which child was actually clicked on.
I'm wondering if there's any such thing for INPC objects, or if not, can one be created.
For instance, if you have a collection which contains thousands of objects which all implement INPC, currently you have to subscribe to each and every one individually. I'm wondering if there's a way around that.
The only thing I can think of is in the setter property for these properties you're interested in, in addition to raising the standard INPC notification, call a delegate in the containing collection and have the collection raise the appropriate notification. That way the consumer would just have to subscribe to a single handler on the collection for any of its children.
My hesitation here is if you're going to do that, why not just make that collection subscribe to the children itself, then re-raise the notification from the collection? My thought however is that calling a delegate directly from the specific setters you're interested in avoids string comparison in the PropertyChanged handler that would delegate such notifications.
Note: This is pseudo-code typed off the top of my head so it may not compile. It's to illustrate a concept/idea, not to be an example of actual code.
public class ItemCollection : ObservableCollection<Item>
{
public EventHandler ChildItemPropertyChanged(object sender, string propertyName);
internal void RaiseChildItemPropertyChanged(object sender, string propertyName)
{
var childItemPropertyChanged = ChildItemPropertyChanged;
if(childItemPropertyChanged != null)
childItemPropertyChanged(sender, propertyName);
}
}
public class Item : INotifyPropertyChanged
{
public ItemCollection OwningCollection;
public Item(ItemCollection owningCollection)
{
OwningCollection = owningCollection;
}
private string _name;
public string Name
{
get{ return _name; }
set
{
if(_name == value)
return;
_name = value;
PropertyChanged(this, "Name");
OwningCollection.RaiseChildItemPropertyChanged(this, "Name");
}
}
}
Thoughts?

Understanding how PropertyChanged mechanism works (workflow)

Clarifications:
1.- I don't know if this has an specific name or word to reference it in English or programming slang, so maybe this can be a duplicate post, since I'm can't look about it.
2.- I'm totally newbie with this stuff, I've never used handlers, so that's part of the problem.
I'm trying to understand how the NotifyPropertyChanged mechanism works. Based on: INotifyPropertyChanged, focusing on the example. (I'm looking it in Spanish, above you can change it to the original English one if it doesn't change auto.
Now I'm going to extract the main code that makes me wonder, and try to analyze it. Hope you can show me where (if exist) i'm wrong and what I can't understand. Let's focus on the class that implements the interface.
// This is a simple customer class that
// implements the IPropertyChange interface.
public class DemoCustomer : INotifyPropertyChanged
{
// These fields hold the values for the public properties.
private Guid idValue = Guid.NewGuid();
private string customerNameValue = String.Empty;
private string phoneNumberValue = String.Empty;
public event PropertyChangedEventHandler PropertyChanged;
// This method is called by the Set accessor of each property.
// The CallerMemberName attribute that is applied to the optional propertyName
// parameter causes the property name of the caller to be substituted as an argument.
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
// The constructor is private to enforce the factory pattern.
private DemoCustomer()
{
customerNameValue = "Customer";
phoneNumberValue = "(312)555-0100";
}
// This is the public factory method.
public static DemoCustomer CreateNewCustomer()
{
return new DemoCustomer();
}
// This property represents an ID, suitable
// for use as a primary key in a database.
public Guid ID
{
get
{
return this.idValue;
}
}
public string CustomerName
{
get
{
return this.customerNameValue;
}
set
{
if (value != this.customerNameValue)
{
this.customerNameValue = value;
NotifyPropertyChanged();
}
}
}
public string PhoneNumber
{
get
{
return this.phoneNumberValue;
}
set
{
if (value != this.phoneNumberValue)
{
this.phoneNumberValue = value;
NotifyPropertyChanged();
}
}
}
Well, what do I understand? (or believe it).
From:
public event PropertyChangedEventHandler PropertyChanged;
1.- PropertyChanged is a method. The one which would be executed when ProperyChanged event triggers.
Doubt: But this method is never implemented...
From:
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
2.- NotifyPropertyChanged is a method. Created by us, can have any name we desire. This method will be launched by us when a property gets modified.
Question: Does this method triggers ProperyChanged event?
Doubt: For me, as I can see there, no one launches this event, but the method we've created to be launch when triggers. But since it doesn't triggers, and instead of it we directly launch the method...
Mixture final think: NotifyPropertyChanged throws the event using the Hanlder, in order to be caught by the "superior entity" (the binding source in the example code), which receives the modified property in order to can update it. Then, if I want to know which elements/classes can be aware of this kind of events, what can I do?
I think this last one is the correct one, but since I'm not and expert but my thinking while trying to understand it and writing this question, I'd like you to correct me.
Thanks so much!
UPDATED
Thanks so much to all! Then, Can I suscribe to the event with the method i want? I've tried:
objetos[usados] = new ItemDB();
objetos[usados].PropertyChanged += mensaje();
With:
public async void mensaje(string cadena)
{
var dlg = new ContentDialog(){
Title = "My App",
Content = cadena,
PrimaryButtonText = "Yes",
SecondaryButtonText = "No"
};
var result = await dlg.ShowAsync();
}
But then VS says:
Error 1 Ninguna sobrecarga correspondiente a 'mensaje' coincide con el 'System.ComponentModel.PropertyChangedEventHandler' delegado
Translated:
Error 1 No one overload corresponding to 'mensaje' matches with 'System.ComponentModel.PropertyChangedEventHandler' delegate
Why doesn't it work, since my event is given with an arg that is a string, and mensaje receives as an argument and string?
I recommend you look up Events and Delegates in C# for further reading.
public event PropertyChangedEventHandler PropertyChanged;
PropertyChanged ist an EventHandler, which is a delegate. Other code can register here and get executed when the delegate is called.
So what happens with INotifyPropertyChanged is:
Some Code (propably the binding in Xaml) registers for the PropertyChanged event:
yourobject.PropertyChanged += MethodThatShouldBeCalledWhenThePropertyChanges;
(This is most properly auto generated somewhere, because it happens from xaml, but you could as well to it this way by hand.)
In the NotifyPropertyChanged Method, the event delegate gets executed.
It simply executes all methods that were added to the event.
So to answer your questions:
Yes, the code in NotifyPropertyChanged "triggers" the event. It calls every method that was added to the event.
Any code can register for events.
As of your Update:
I again recommend reading into delegates.
You can think of delegates as Method Interface. It defines that a method has to take specific parameter types to match the delegate.
PropertyChanged is of type PropertyChangedEventHandler which takes an object and a PropertyChangedEventArgs parameter.
So any method like this is suitable:
void MethodName(
Object sender,
PropertyChangedEventArgs e
)
First, you are correct, NotifyPropertyChanged is a user-defined function. It is indented just to avoid doubling of logic as soon as more properties are used. Second, NotifyPropertyChanged will not be executed when the event triggers, but the other way round; as soon as NotifyPropertyChanged is called, the event is triggered. If a suitable control is bound, it will, so to speak, consume the event and probably update itself. The event can be seen as an outlet on which other code can register callbacks. Furthermore, the Attribute CallerMemberName was introduced with .NET 4.5. The same result can be achieved without using it, but for each call of NotifyPropertyChanged the name of the property would have to be given explicitly.

Simple-bound .NET data binding not working

Technology: .NET 4, C#, WinForms, Visual Studio 2010
I am in the processing of learning data binding and have been unable to get even a simple example to work as expected. I have a form with a label that I am binding to that shows the current mouse cursor coordinates.
public partial class Form1 : Form, INotifyPropertyChanged
{
[Bindable(true)]
private String cursorPosition;
public String CursorPosition
{
get
{
return cursorPosition;
}
set
{
cursorPosition = value;
NotifyPropertyChanged("CursorPosition");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public Form1()
{
InitializeComponent();
}
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
CursorPosition = "(" + Convert.ToString(e.X) + " , " + Convert.ToString(e.Y) + ")";
}
private void NotifyPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
From the designer, I have set the label's Data Binding to bind the Text property to form1BindingSource - CursorPosition. What am I missing?
Edit: Updated code snippet.
From the designer, I have set the label's Data Binding to bind the Text property to form1BindingSource - CursorPosition. What am I missing?
Have you set:
form1BindingSource.DataSource = this; // (or whatever the real data source is)
e.g. in the form's constructor, after InitializeComponent?
(This assumes that your Form1 instance is the data source, and you're binding the controls to it via a BindingSource.)
A few further detail suggestions:
Choosing the form itself as data source is somewhat unusual. IMHO it's better to separate all bound-to properties into a separate, non-UI data object. This then allows you to create a reusable base type for the INotifyPropertyChanged implementation.
As #rfmodulator says in his answer, the BindableAttribute is attached to the field:
[Bindable(true)]
private String cursorPosition;
public String CursorPosition
…
You probably meant to attach it to the property:
private String cursorPosition;
[Bindable(true)]
public String CursorPosition
…
Your setter should probably look like this:
set
{
if (!string.Equals(cursorPosition, value) // +
{ // +
cursorPosition = value;
NotifyPropertyChanged("CursorPosition");
} // +
}
That is, only raise the PropertyChanged event when the property value actually changes.
You probably want to change your NotifyPropertyChanged method to this:
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged; // +
if (handler != null) // ~
{
handler(this, new PropertyChangedEventArgs(propertyName)); // ~
}
}
This is because PropertyChanged could in theory change between the null check and the invocation. You can exclude this theoretical possibility by creating a local copy of the event delegate.
P.S.: To be precise, as Jeffrey Richter points out in his book "CLR via C#", a local variable is still not quite enough: Ideally, you'd assign Interlocked.CompareExchange(ref PropertyChanged, null, null) to handler (instead of simply PropertyChanged) because using that method will prevent the JIT code generator from optimizing away the local variable (IIRC).
I assume you want the PropertyChanged event to fire? You are setting the backing variable's value in Mouse_Move, not the property's value. As a result, the call to NotifyPropertyChanged won't get called.
You shouldn't implement INotifyPropertyChanged on components, controls and forms because databinding will rely on the XXXChanged event paradigm to listen for change notification. Internally, databinding uses property descriptors to listen for change events. They hint how the class detects changes in the documentation for the PropertyDescriptor.SupportsChangeEvents property. This has to do with the history of winforms databinding. XXXChanged was the way to do databinding & change notification before .NET 2.0. INotifyPropertyChanged was introduced in 2.0 in favor of the XXXChanged pattern.
The SupportsChangeEvents property indicates whether value change notifications for this property may originate from outside the property descriptor, such as from the component itself, or whether notifications will only originate from direct calls made to the SetValue method. For example, the component may implement the INotifyPropertyChanged interface, or may have an explicit nameChanged event for this property.
You're setting the Bindable attribute on the field but calling NotifyPropertyChanged with the property as the argument.

Short way to write an event?

Typically we use this code:
private EventHandler _updateErrorIcons;
public event EventHandler UpdateErrorIcons
{
add { _updateErrorIcons += value; }
remove { _updateErrorIcons -= value; }
}
Is there a similar shortcut like with automatic properties?
Something like:
public event EventHandler UpdateErrorIcons { add; remove; }
Yep. Get rid of the { add; remove; } part and the backing delegate field and you're golden:
public event EventHandler UpdateErrorIcons;
That's it!
Let me just add that before you asked this question, I hadn't even thought about the fact that the auto-implemented version of events is inconsistent with that of properties. Personally, I would actually prefer it if auto-implemented events worked the way you first attempted in your question. It would be more consistent, and it would also serve as a mental reminder that events are not identical to delegate fields, just like properties are not identical to regular fields.
Honestly, I think you're the rare exception where you actually knew about the custom syntax first. A lot of .NET developers have no clue there's an option to implement your own add and remove methods at all.
Update: Just for your own peace of mind, I have confirmed using Reflector that the default implementation of events in C# 4 (i.e., the implementation that gets generated when you go the auto-implemented route) is equivalent to this:
private EventHandler _updateErrorIcons;
public event EventHandler UpdateErrorIcons
{
add
{
EventHandler current, original;
do
{
original = _updateErrorIcons;
EventHandler updated = (EventHandler)Delegate.Combine(original, value);
current = Interlocked.CompareExchange(ref _updateErrorIcons, updated, original);
}
while (current != original);
}
remove
{
// Same deal, only with Delegate.Remove instead of Delegate.Combine.
}
}
Note that the above utilizes lock-free synchronization to effectively serialize add and remove calls. So if you're using the latest C# compiler, you don't need to implement add/remove yourself even for synchronization.
public event EventHandler UpdateErrorIcons;
is just fine
you can use
yourObbject.UpdateErrorIcons += YourFunction;
add {} and remove {} are used only in special cases where you need to handle event hookups manually. Us mere mortals normally just use public event EventHandler UpdateErrorIcons; where "EventHandler" is the delegate of choice.
For instance:
public delegate void MyEventDelegate(object sender, string param1);
public event MyEventDelegate MyEvent;
Note that because MyEvent is null if it doesn't have any listeners you need to check if it is null before invoking it. A standard method for doing this check is:
public void InvokeMyEvent(string param1)
{
MyEventDelegate myEventDelegate = MyEvent;
if (myEventDelegate != null)
myEventDelegate(this, param1);
}
A key element in this check is to make a copy of the object in question first and then work only on the copy. If not you could get a rare race condition where another thread unhooks between your if and your call.

Categories