View bound to non-INotifyPropertyChanged, still updating [duplicate] - wpf

I created a ViewModel and bound its property to two textboxes on UI. The value of the other textbox changes when I change the value of first and focus out of the textbox but I'm not implementing INotifyPropertyChanged. How is this working?
Following is XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Name}" />
</StackPanel>
</Window>
And following is my ViewModel
class ViewModel
{
public string Name { get; set; }
}

I tested it, you are right. Now i searched for it on the web, and found this.
Sorry to take so long to reply, 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.
Hope this clears things up a little bit.
So basically you can do this, as long as its a plain CLR object. Pretty neat but totally unexpected - and i have done a bit of WPF work the past years. You never stop learning new things, right?
As suggested by Hasan Khan, here is another link to a pretty interesting article on this subject.
Note this only works when using binding. If you update the values from code, the change won't be notified. [...]
WPF uses the much lighter weight PropertyInfo class when binding. If you explicitly implement INotifyPropertyChanged, all WPF needs to do is call the PropertyInfo.GetValue method to get the latest value. That's quite a bit less work than getting all the descriptors. Descriptors end up costing in the order of 4x the memory of the property info classes. [...]
Implementing INotifyPropertyChanged can be a fair bit of tedious development work. However, you'll need to weigh that work against the runtime footprint (memory and CPU) of your WPF application. Implementing INPC yourself will save runtime CPU and memory.
Edit:
Updating this, since i still get comments and upvotes now and then from here, so it clearly is still relevant, even thouh i myself have not worked with WPF for quite some time now. However, as mentioned in the comments, be aware that this may cause memory leaks. Its also supposedly heavy on the Reflection usage, which has been mentioned as well.

I just found out that this also works in WinForms, kinda :/
public class Test
{
public bool IsEnabled { get; set; }
}
var test = new Test();
var btn = new Button { Enabled = false, Text = "Button" };
var binding = new Binding("Enabled", test, "IsEnabled");
btn.DataBindings.Add(binding);
var frm = new Form();
frm.Controls.Add(btn);
test.IsEnabled = true;
Application.Run(frm);
Strangely though, this doesn't disable the button:
btn.Enabled = false;
This does:
test.IsEnabled = false;

I can explain why the property is updated when focus changes: all Bindings have an UpdateSourceTrigger property which indicates when the source property will be updated. The default value for this is defined on each DependencyProperty and for the TextBox.Text property is set to LostFocus, meaning that the property will be updated when the control loses focus.
I believe UrbanEsc's answer explains why the value is updated at all

Related

Rogue PropertyChanged notifications from ViewModel [duplicate]

I created a ViewModel and bound its property to two textboxes on UI. The value of the other textbox changes when I change the value of first and focus out of the textbox but I'm not implementing INotifyPropertyChanged. How is this working?
Following is XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Name}" />
</StackPanel>
</Window>
And following is my ViewModel
class ViewModel
{
public string Name { get; set; }
}
I tested it, you are right. Now i searched for it on the web, and found this.
Sorry to take so long to reply, 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.
Hope this clears things up a little bit.
So basically you can do this, as long as its a plain CLR object. Pretty neat but totally unexpected - and i have done a bit of WPF work the past years. You never stop learning new things, right?
As suggested by Hasan Khan, here is another link to a pretty interesting article on this subject.
Note this only works when using binding. If you update the values from code, the change won't be notified. [...]
WPF uses the much lighter weight PropertyInfo class when binding. If you explicitly implement INotifyPropertyChanged, all WPF needs to do is call the PropertyInfo.GetValue method to get the latest value. That's quite a bit less work than getting all the descriptors. Descriptors end up costing in the order of 4x the memory of the property info classes. [...]
Implementing INotifyPropertyChanged can be a fair bit of tedious development work. However, you'll need to weigh that work against the runtime footprint (memory and CPU) of your WPF application. Implementing INPC yourself will save runtime CPU and memory.
Edit:
Updating this, since i still get comments and upvotes now and then from here, so it clearly is still relevant, even thouh i myself have not worked with WPF for quite some time now. However, as mentioned in the comments, be aware that this may cause memory leaks. Its also supposedly heavy on the Reflection usage, which has been mentioned as well.
I just found out that this also works in WinForms, kinda :/
public class Test
{
public bool IsEnabled { get; set; }
}
var test = new Test();
var btn = new Button { Enabled = false, Text = "Button" };
var binding = new Binding("Enabled", test, "IsEnabled");
btn.DataBindings.Add(binding);
var frm = new Form();
frm.Controls.Add(btn);
test.IsEnabled = true;
Application.Run(frm);
Strangely though, this doesn't disable the button:
btn.Enabled = false;
This does:
test.IsEnabled = false;
I can explain why the property is updated when focus changes: all Bindings have an UpdateSourceTrigger property which indicates when the source property will be updated. The default value for this is defined on each DependencyProperty and for the TextBox.Text property is set to LostFocus, meaning that the property will be updated when the control loses focus.
I believe UrbanEsc's answer explains why the value is updated at all

Why does the binding update without implementing INotifyPropertyChanged?

I created a ViewModel and bound its property to two textboxes on UI. The value of the other textbox changes when I change the value of first and focus out of the textbox but I'm not implementing INotifyPropertyChanged. How is this working?
Following is XAML
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Name}" />
<TextBox Text="{Binding Name}" />
</StackPanel>
</Window>
And following is my ViewModel
class ViewModel
{
public string Name { get; set; }
}
I tested it, you are right. Now i searched for it on the web, and found this.
Sorry to take so long to reply, 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.
Hope this clears things up a little bit.
So basically you can do this, as long as its a plain CLR object. Pretty neat but totally unexpected - and i have done a bit of WPF work the past years. You never stop learning new things, right?
As suggested by Hasan Khan, here is another link to a pretty interesting article on this subject.
Note this only works when using binding. If you update the values from code, the change won't be notified. [...]
WPF uses the much lighter weight PropertyInfo class when binding. If you explicitly implement INotifyPropertyChanged, all WPF needs to do is call the PropertyInfo.GetValue method to get the latest value. That's quite a bit less work than getting all the descriptors. Descriptors end up costing in the order of 4x the memory of the property info classes. [...]
Implementing INotifyPropertyChanged can be a fair bit of tedious development work. However, you'll need to weigh that work against the runtime footprint (memory and CPU) of your WPF application. Implementing INPC yourself will save runtime CPU and memory.
Edit:
Updating this, since i still get comments and upvotes now and then from here, so it clearly is still relevant, even thouh i myself have not worked with WPF for quite some time now. However, as mentioned in the comments, be aware that this may cause memory leaks. Its also supposedly heavy on the Reflection usage, which has been mentioned as well.
I just found out that this also works in WinForms, kinda :/
public class Test
{
public bool IsEnabled { get; set; }
}
var test = new Test();
var btn = new Button { Enabled = false, Text = "Button" };
var binding = new Binding("Enabled", test, "IsEnabled");
btn.DataBindings.Add(binding);
var frm = new Form();
frm.Controls.Add(btn);
test.IsEnabled = true;
Application.Run(frm);
Strangely though, this doesn't disable the button:
btn.Enabled = false;
This does:
test.IsEnabled = false;
I can explain why the property is updated when focus changes: all Bindings have an UpdateSourceTrigger property which indicates when the source property will be updated. The default value for this is defined on each DependencyProperty and for the TextBox.Text property is set to LostFocus, meaning that the property will be updated when the control loses focus.
I believe UrbanEsc's answer explains why the value is updated at all

DataBinding Text Property of UserControl to ObservableCollection does not update

I have created a UserControl, which is to display a converted string value based on the contents of a bound ObservableCollection. Everything works when the application loads; my IValueConverter is called and produces the correct string result, which is displayed correctly in my UserControl. However if the ObservableCollection contents change, my control is not updated.
Also, before I created this control, I had the same behaviour, but binding the Content property of a regular Button control, and this also worked correctly and updated as expected.
Any ideas what I am missing to get the same thing with my UserControl?
The control property looks like;
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(MyUserControl));
public string Text
{
get { return GetValue(TextProperty) as string; }
set { SetValue(TextProperty, value);
}
The relevant section in the UserControl XAML (which displays the converted string value) is;
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type Controls:MyUserControl}}, Path=Text}" />
And the control is created in a separate Window like so;
<CoreControls:MyUserControl
Name="myControl"
Text="{Binding Path=ObservableCollectionInstance, Converter={StaticResource MyValueConverter}, Mode=OneWay}" />
I would use ElementName instead of RelativeSource in your binding, since you have named your user control. Also, you are trying to bind a collection to a <Textbox>. a <Textbox> is designed to display a single item. this is probably why its not working. ObservableCollection fires CollectionChanged events, not PropertyChanged. Even if it did respond, you are still going to have problems because ObservableCollection does not notify when an item contained in it has property changes--only when items are added/removed etc (think, the collection itself changes). If this is the behavior you want, you are going to have to write some code.
EDIT
after your comments, it sounds to me like even though you set it to OneWay binding mode, its acting like OneTime binding mode.
I would try this to help you debug it:
add this xmlns:
xmlns:diagnostics="clr-namespace:System.Diagnostics;assembly=WindowsBase"
and then, in your binding add this:
diagnostics:PresentationTraceSources.TraceLevel=High
here is an article on debugging bindings.
the other thing you could do is set breakpoints in your converter. see if its actually updating when you add/remove things to your collection. I would be willing to bet that its bc the ObservableCollection is NOT firing PropertyChanged events and that the initial update occurs because its not based on an update event.
ObservableCollection notifies only in case if items get added or removed. It is used to observe a collection. They are more suited for content controls. Read about it here. You are talking about observing a property, which needs INotifyPropertyChanged. Posting more code might help, like how are you changing the value of the collection.
Thanks for the tips guys.
I managed to work out a solution; I can handle the CollectionChanged event on the ObservableCollection and then explicitly update the target with something like;
BindingExpression exp = myControl.GetBindingExpression(MyUserControl.TextProperty);
if (null != exp) exp.UpdateTarget();
As noted, most likely, binding on the Text property is only listening to PropertyChanged events, not NotifyCollectionChanged events, but this solution does the trick.

Do WPF controls use weak events in their bindings?

When I use databinding in WPF, my target controls are listening for events on the binding source. For example, I may have a ListView listening for CollectionChanged events on a ObservableCollection.
If the lifetime of an event source is expected to exceed the lifetime of an event listener, there is a potential memory leak, and the weak event pattern should be used.
Does WPF databinding follow the weak event pattern? If my ObservableCollection lives longer than my ListView, will my ListView be garbage collected?
Here is why I suspect that WPF controls do not implement the weak event pattern. If they did, I would expect both DerivedListView Collected! and DerivedTextBlock Collected! to be output to the console. Instead, only DerivedTextBlock Collected! is.
After fixing a bug in the code, both objects are collected. I'm not sure what to think.
Window1.xaml.cs
using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
namespace LeakDetector
{
public class DerivedListView : ListView
{
~DerivedListView()
{
Console.WriteLine("DerivedListView Collected!");
}
}
public class DerivedTextBlock : TextBlock
{
~DerivedTextBlock()
{
Console.WriteLine("DerivedTextBlock Collected!");
}
}
public partial class Window1 : Window
{
// The ListView will bind to this collection and listen for its
// events. ObColl will hold a reference to the ListView.
public ObservableCollection<int> ObColl { get; private set; }
public Window1()
{
this.ObColl = new ObservableCollection<int>();
InitializeComponent();
// Trigger an event that DerivedListView should be listening for
this.ObColl.Add(1);
// Get rid of the DerivedListView
this.ParentBorder.Child = new DerivedTextBlock();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
this.ParentBorder.Child = null;
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
GC.WaitForPendingFinalizers();
GC.Collect(GC.MaxGeneration, GCCollectionMode.Forced);
Console.WriteLine("Done");
}
}
}
Window1.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:LeakDetector"
x:Class="LeakDetector.Window1"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Height="300" Width="300"
Title="Leak Detector">
<Border x:Name="ParentBorder">
<local:DerivedListView ItemsSource="{Binding Path=ObColl}" />
</Border>
</Window>
In essence, the WPF controls themselves do not have anything to do with weak events. Instead, there are certain classes related to WPF's Binding engine that implement the weak event pattern. The class PropertyChangedEventManager implements WeakEventManager. And if you use Reflector, you'll see that several classes implement IWeakEventListener in the MS.Internal.Data namespace (one in particular is the MS.Internal.Data.PropertyPathWorker class which directly uses the PropertyChangedEventManager). These objects are used by WPF internally to do Data Binding.
ItemsControls and CollectionChanged events are a different story and has nothing to do with Bindings. See, you could do something like "listView.ItemsSource = myObservableCollection" in the code behind and the collection-changed notification will still work. No Binding objects are involved here at all. Here, a different set of "weak-event-related classes" are in play. ItemCollection and ItemContainerGenerator implement IWeakEventListener, and they work in conjunction with the CollectionChangedEventManager(which implements WeakEventManager).
The second sentence of the MSDN article to which you linked pretty clearly states that WPF does use the Weak Event Pattern. In fact, it goes so far as to say that WPF introduced the pattern.
Edit:
I was hoping to find some documentation which explicitly states "WPF controls implement the weak event pattern." – emddudley
After doing some research, I think the answer to that question is "no", and I think the reason the answer is "no" is that WPF doesn't expect UI controls to be transitory. While there is a CollectionChangedEventManager class built specifically for weak events against the CollectionChanged event, none of the controls that support databinding appear to implement IWeakEventListener, which would be necessary to use weak events against the collection.
I think the pattern and usage are built for a ViewModel rather than a View, which is more likely to be transitory than a View.
Edit2:
After fixing a bug in the code, both objects are collected. Therefore I believe that WPF controls use the weak event pattern.
Interesting result. If they do implement Weak Events, they must do it internally.

Two-way binding in WPF

I cannot get a two-way bind in WPF to work.
I have a string property in my app's main window that is bound to a TextBox (I set the mode to "TwoWay").
The only time that the value of the TextBox will update is when the window initializes.
When I type into the TextBox, the underlying string properties value does not change.
When the string property's value is changed by an external source (an event on Click, for example, that just resets the TextBox's value), the change doesn't propagate up to the TextBox.
What are the steps that I must implement to get two-way binding to work properly in even this almost trivial example?
Most probably you're trying to bind to a .net CLR property instead of a WPF dependencyProperty (which provides Change Notification in addition to some other things).
For normal CLR property, you'd need to implement INotifyPropertyChanged and force update on the textbox in the event handler for PropertyChanged.
So make your object with the property implement this interface, raise the event in the property setter. (So now we have property change notification)
Make sure the object is set as the DataContext property of the UI element/control
This threw me off too when I started learning about WPF data binding.
Update: Well OP, it would have been a waste of time if i was barking up the wrong tree.. anyways now since you had to dig a bit.. you'll remember it for a long time. Here's the code snippet to round off this answer. Also found that updating the textbox happens automatically as soon as I tab-out.. You only need to manually subscribe to the event and update the UI if your datacontext object is not the one implementing INotifyPropertyChanged.
MyWindow.xaml
<Window x:Class="DataBinding.MyWindow" ...
Title="MyWindow" Height="300" Width="300">
<StackPanel x:Name="TopLevelContainer">
<TextBox x:Name="txtValue" Background="AliceBlue" Text="{Binding Path=MyDotNetProperty}" />
<TextBlock TextWrapping="Wrap">We're twin blue boxes bound to the same property.</TextBlock>
<TextBox x:Name="txtValue2" Background="AliceBlue" Text="{Binding Path=MyDotNetProperty}" />
</StackPanel>
</Window>
MyWindow.xaml.cs
public partial class MyWindow : Window, INotifyPropertyChanged
{
public MyWindow()
{
InitializeComponent();
this.MyDotNetProperty = "Go ahead. Change my value.";
TopLevelContainer.DataContext = this;
}
private string m_sValue;
public string MyDotNetProperty
{
get { return m_sValue; }
set
{
m_sValue = value;
if (null != this.PropertyChanged)
{
PropertyChanged(this, new PropertyChangedEventArgs("MyDotNetProperty"));
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
I feel the need to add some precision:
"Two ways" data binding is more than "One way" data binding.
"One way" data binding is a binding from a source to a dependency property. The source must implement INotifyPropertyChanged, in order to get change propagation from source to target.
To get the " 2 way" , so to get a propagation from Target to Source, it depends on the binding mode which you set on the Binding . If you don't set any BindingMode for your binding, the default Binding mode will be used, and this default mode is a characteristics for your target Dependency Property.
Example:
A Textbox bound to a string property, called "MyTextProperty".
In the code, you bind Textbox.Text DependencyProperty to "MyTextProperty" on object "MyObject"
--> "one way" binding : the setter of "My TextProperty" must raise an event Property Changed,and "MyObject" must implement INotifyPropertyChanged.
--> "2 ways data binding": in addition to what is needed for "One way", bindingMode must be set to "2 ways". In this special case, the Text DependencyProperty for Textbox does have "2 ways" as default mode, so there is nothing else to do !
We might need to see the code. Does your string property raise a PropertyChanged event? Or (even better) is it implemented as a DependencyProperty? If not, the bound TextBox won't know when the value changes.
As for typing into the TextBox and not seeing the property's value change, that may be because your TextBox isn't losing focus. By default, bound TextBoxes don't write their values back to the source property until focus leaves the control. Try tabbing out of it and seeing if the property value changes.
Make sure that the binding specifies two way and when the property has a change, it is immediately transmitted to the holding property.
<TextBox Text="{Binding TextBuffer,
UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay}"/>
The above assures that the TextBox input control Text property binds to, then sends the changes back to the string property named TextBuffer in an immediate, PropertyChanged, and TwoWay fashion.

Resources