INotifyPropertyChanged with a property that's a class? - c#

If I register to be notified of a property's change, it will only notify when the actual property is reassigned. So if I have a property that's a textbox, it won't notify if the text of the textbox changes, right? Is there any way to make it work this way?

If you are interested in specific properties of an object then you should be using a mechanism like INotifyPropertyChanged on the value itself. Unfortunately though in this case TextBox from WinForms doesn't implement INotifyPropertyChanged. In order to listen for changes to its Text property you need to subscribe to the TextChanged event

I have had a hard time imagining why a class would expose a property of type TextBox. Anyhow if you have ended up with such a design, you could simply add two properties, each for the TextBox itself and the text inside and then listen to TextBox's TextChanged event and fire your NotifyPropertyChanged thereupon.
I do feel however that you need to rethink your approach. If your class exposes a property of TextBox type, there should really be places where you actually assign a new TextBox to a class instance and upper layers listening to this change. I don't think that would be the case however. You'd almost certainly be looking for text changes and should therefore expose a property of type string.

Related

INotifyPropertyChanged vs Two way binding

I am newbie in c# and i want to know why we have to implement INotifyPropertyChanged interface when we use the TwoWay binding ?? and for the OneWay also ??
Thank you
In brief to support OneWay/TwoWay bindings, the underlying data must implement INotifyPropertyChanged.
Then the OneWay/TwoWay binding is just to choose the bind direction, you can find more here :
Various wpf binding modes
INotifyPropertyChanged,like the name, is to notify your client that your property has changed, see MSDN
You will need it for updating your UI when properties change.
OneWay(Source to Target): Propertychange will cause UI update and UI operation will NOT cause propertychange. *
TwoWay(Both way): Proerty and UI are fully binded, any of them change will affect the other one.
Binding works as long as you implement INotifyPropertyChanged for your property in this case.
If you don't, nothing will change even if you use Twoway.
Implementing INotifyPropertyChanged just offers classes (others than the one implementing it) the possibility to react on property changes.
This is not possible if that interface is not implemented because if a class instance, say A sets a property on B, a third class instance C cannot track that information. Setting that property is now only a concern of A and B. If Chowever knows that B does implement INotifyPropertyChanged, it can simply add an event handler to the event PropertyChanged (which is part of the interface) and react on it - still hoping that B will throw the event as expected.
Bindings need that information to update the model (data) or the view depending where the change happened. So basically, they are C listening for changes of other objects (A & B).

TextBox TextChanged Event Problems

I'm using a basic TextBox that is bound to an object. Basically, what I want to do is call a method every time the text in the box is edited and the user de-selects the box or when the underlying bound data is edited. What I am using right now is the TextChanged event, but this has a few problems:
It is called when the TextBox is first created, and I don't want this.
It is called every time a new character is added, and I only want it called when the underlying bound data is changed (which seems to be whenever focus shifts from the box).
How can I accomplish this?
EDIT: I've tried several other TextBox properties like Get/LostFocus but they never seem to fire.
Also, I don't want to put this method call in the Setter of the Property, because the underlying data is something that is logically separate from the UI of this project and I don't want any method calls that relate to doing computations for the UI.
The event LostFocus fires when the focus is shifted from the current element. I tried it and its working fine.
As jods says, the best way to bind your TextBox's Text to ViewModel's property. The Code are:
View:
<TextBox x:Name="TextBox1" Text="{Binding Path=Text1,Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
ViewModel:
public string Text1
{
get { return _text1; }
set
{
_text1 = value;
RaisePropertyChanged("Text1");
}
}
View code behind:
private void ViewModelPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Text1")
{
//Call UI related method...
}
}
In this way, it satisfy your two conditions:
1. Every time when you edit TextBox and lose the focus, Setter of Text1 will be called and ViewModel will raise PropertyChanged event.
2. When underlying Text1 is changed. Text1 will also raise the event so View can know it.
Also it can avoid your two concerns:
1. In the first time binding, only getter of Text1 is called. No event is raised.
2. Setter of Text1 is only called after TextBox is lost focus.
every time the text in the box is edited and the user de-selects the box
Hmmm AFAIK it's a standard behaviour of TextBox if you bind text like that: Text={Binding Property}
when the underlying bound data is edited
You can provide this functionality inside setter of your property.
Best design is to listen for changes in the underlying bound property. You can do that without changing the setter if you use a DependencyProperty or if your object implements INotifyPropertyChanged.
When the underlying property changes (LostFocus by default, or each char at a time) is a binding option.
If you don't want to follow my advice of listenning for changes in your (view-)model, you could subscribe to GotFocus and LostFocus events. Save the current value when you get focus, compare with current value when you lose it. If it's different -> do what it is you want to do.
I am not sure what you are finally trying to achieve but I am going to take a guess at this. If you are following an MVVM pattern then, then it seems like you can achieve what you want by using the updateSourceTrigger property of the binding. If you are not using MVVM then you might what to take a look at using MVVM

How to bind a WPF control value to a method?

Imagine I have a TextBox that it's Text should be equal to the number of running processes in the machine.
How to make it to update without using timers? Is there a way using Dependency Property or Bindings?
I'm not sure what this has to with binding to a method.
You'd have to keep calling the method on a timer, just the same.
You can set the DataContext to an object that implements INotifyPropertyChanged and exposes a property with the data you want (the getter can, of course, call a method).
Without a timer, you'll need an event to which your data object can subscribe, and then you can raise a notification that the property of interest has changed each time the event fires, and the UI element bound to that property will be updated.

C# - Events Question

Can any C# object be set up such that an event can be tied to it to fire when it's value changes? If so, how is this done? For example, let's take a very simple example. Say I have a variable declared as follows:
int i;
Is it possible to create an event that fires any time the value of i changes?
Thanks.
Well, you can't change fields so that events are fired when the value changes.
On the other hand, you can easily make it so that when a property changes, an event is fired. Only the author of the class containing the property can do this, however1 - you can't attach an event to an arbitrary existing class.
1 A slight exception would be a virtual property, which could be overridden solely for the purpose of raising the event. That would be pretty rare though.
Have a look at the INotifyPropertyChanged interface that can be implemented by a class and called by - at least some of - its properties to notify listeners that some values changed.
Another option would be to use the Observer pattern.
Grz, Kris.
Take a look at the PropertyChangedEvent pattern.

WPF Databinding Magic

I have ObservableCollection<Foo> that is bound to an ItemsControl (basically displaying a list).
Foo mostly looks like this (there are other members but it doesn't implement any interfaces or events):
class Foo
{
public string Name { get; set; }
//...
}
When the user clicks on an item I open a dialog where the user can edit Foo's properties (bound to a small viewmodel with a Foo property for the selected item), the Xaml looks like this:
<TextBox Text="{Binding Foo.Name,Mode=TwoWay}"
Grid.Column="1" Grid.Row="0" Margin="2" />
The really strange thing is, when the user edits the name, the value in the list changes! (not while typing but after the focus leaves the field)
How does it do that? I haven't implemented the INotifyPropertyChanged interface on the Foo object!
So far I checked that it doesn't just refresh the whole list - only the selected item. But I don't know where I could set a breakpoint to check who's calling.
Update: thanks to casperOne for the link to the solution! I'll add a summary here in case it goes 404:
[..] actually you are encountering a another hidden aspect of WPF, that's it WPF's data binding engine will data bind to PropertyDescriptor instance which wraps the source property if the source object is a plain CLR object and doesn't implement INotifyPropertyChanged interface. And the data binding engine will try to subscribe to the property changed event through PropertyDescriptor.AddValueChanged() method. And when the target data bound element change the property values, data binding engine will call PropertyDescriptor.SetValue() method to transfer the changed value back to the source property, and it will simultaneously raise ValueChanged event to notify other subscribers (in this instance, the other subscribers will be the TextBlocks within the ListBox.
And if you are implementing INotifyPropertyChanged, you are fully responsible to implement the change notification in every setter of the properties which needs to be data bound to the UI. Otherwise, the change will be not synchronized as you'd expect.
This is a total guess, but I'm thinking that because you have two-way binding enabled, WPF is now aware of when it makes changes, and will update other items it knows is bound to the same instance.
So because you have changed the value of the Name property through the textbox, and WPF knows when you have changed that value, it does its best to update whatever else it knows is bound to it.
It uses reflection to set the value of that property. INotifyPropertyChanged is only needed if the TextBox needs to be informed of a change in the Name property of the Foo class.
Because they're databound to the same object. If you change the binding to
{Binding Foo.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
then they'll be in synch when the user types in the textbox.

Categories