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.
Related
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.
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.
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.
I've got similar situation to this, but in Touch. Trying to deal with that via INotifyPropertyChanged though.
My code is the following:
set.Bind(txtSearch).For(x => x.Text).To(x => x.SearchText);
where txtSearch is my custom wrapper of UISearchBar. So, I can not inherit from MvxNotifyPropertyChanged as I already inherit from UIView (the wrapper is view).
Text property is:
public string Text { get
{
return _search.Text;
} set
{
_search.Text = value;
RaisePropertyChanged(() => Text);
}
}
and I fire it on the SearchBar text changing (which works).
I've also added the following:
public event PropertyChangedEventHandler PropertyChanged;
protected IMvxMainThreadDispatcher Dispatcher
{
get { return MvxMainThreadDispatcher.Instance; }
}
protected void InvokeOnMainThread(Action action)
{
if (Dispatcher != null)
Dispatcher.RequestMainThreadAction(action);
}
protected void RaisePropertyChanged<T>(Expression<Func<T>> property)
{
var name = this.GetPropertyNameFromExpression(property);
RaisePropertyChanged(name);
}
protected void RaisePropertyChanged(string whichProperty)
{
var changedArgs = new PropertyChangedEventArgs(whichProperty);
RaisePropertyChanged(changedArgs);
}
protected void RaisePropertyChanged(PropertyChangedEventArgs changedArgs)
{
// check for subscription before going multithreaded
if (PropertyChanged == null)
return;
InvokeOnMainThread(
() =>
{
var handler = PropertyChanged;
if (handler != null)
handler(this, changedArgs);
});
}
But when everything gets to RaisePropertyChanged, then I see that PropertyChanged is empty (so, seems no code is subscribed for my object). Which, of course, makes no notifications further.
I have similar situation but with some object inherited directly from MvxNotifyPropertyChanged, which seems working fine. Does that mean, that MvvmCross only can deal with such objects but not ones which generally use INotifyPropertyChanged?
Thank you!
INotifyPropertyChanged is used on the ViewModel side for property changes.
On the View side, MvvmCross uses DependencyProperty bindings on Windows, and C# methods, properties and events on the Xamarin platforms.
INotifyPropertyChanged isn't provided by default on the View side - since no off-the-shelf View objects support INotifyPropertyChanged, then there was no point in trying to bind to it within any of the MvvmCross View platforms.
However, the binding system is extensible - so if anyone wants to write INotifyPropertyChanged based views and wants to include a custom INotifyPropertyChanged binding for the View side, then they can do that following the steps similar to In MvvmCross how do I do custom bind properties and following examples linked from https://speakerdeck.com/cirrious/custom-bindings-in-mvvmcross
If they want to write an INotifyPropertyChanged-based system for the View side, then I'm sure this could be achieved using a custom binding approach - but it's not something I've personally done. I would expect such a custom binding to work both for INotifyPropertyChanged and for MvxNotifyPropertyChanged too (since MvxNotifyPropertyChanged implements INotifyPropertyChanged) - but I guess it would be up to the author to decide on the mechanics of that.
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.