UpdateSourceTrigger's Default vs PropertyChanged? - wpf

<TextBlock Name="txtName" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" />
"Name" is the property of an object which is bound with the TextBlock at runtime. I have implemented INotifyPropertyChanged so the code is working fine. My question is: if I replace PropertyChanged to Default will it still work? What's the difference between them?

According to MSDN, the UpdateSourceTrigger's default value is PropertyChanged for most properties and LostFocus for the TextBox.Text property.
In your case, you're probably binding to a property for which the default is already set to PropertyChanged, so you won't see any difference.

PropertyChanged is telling Binding that whenever you receive PropertyChanged notification for that property, update it's value on destination.
For some controls, like TextBox, using Default, it only updates binding destination when for example, it loses focus. When you set UpdateTrigger='PropertyChanged' on it, it will update binding destination while you are typing.

For TextBox Control
When we use UpdateSourceTrigger=Default means when source object loses focus, value in target will get updated.
When we use UpdateSourcetrigger=PropertyChanged means when source object text changes(even when we type a single character) immediately than change will be reflected in target.
Above case is for TextBox control as default for most control is PropertyChanged only

Related

Is WPF UpdateSourceTrigger always needed to notify model of changes in collection?

Question: Was UpdateSourceTrigger always necessary to have properties update the source? I seem to recall that Mode=TwoWay was enough a long time ago. But now, I have to UpdateSourceTrigger=PropertyChanged? Maybe I'm losing it...
<DataGridTemplateColumn Header="Hub" Width="SizeToHeader">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox x:Name="XHub" IsChecked="{Binding Hub, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
When I omit that part of the binding the model is never called when a value in the ObservableCollection changes.
Both Mode and UpdateSourceTrigger properties of the binding depends on the dependency property you are binding to. According to MSDN:
The default is Default, which returns the default UpdateSourceTrigger value of the target dependency property. However, the default value for most dependency properties is PropertyChanged, while the Text property has a default value of LostFocus.
A programmatic way to determine the default UpdateSourceTrigger value of a dependency property is to get the property metadata of the property using GetMetadata and then check the value of the DefaultUpdateSourceTrigger property.
So in your case you are binding to IsChecked that is defined in ToogleButton class as following:
public static readonly DependencyProperty IsCheckedProperty =
DependencyProperty.Register("IsChecked", typeof (bool?), typeof (ToggleButton),
(PropertyMetadata) new FrameworkPropertyMetadata(
BooleanBoxes.FalseBox,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault | FrameworkPropertyMetadataOptions.Journal,
new PropertyChangedCallback(ToggleButton.OnIsCheckedChanged)));
So BindsTwoWayByDefault makes Mode=TwoWayredundant, while
querying metadata:
var def = ((FrameworkPropertyMetadata)CheckBox.IsCheckedProperty.GetMetadata(typeof(CheckBox))).DefaultUpdateSourceTrigger;
results in PropertyChanged, that makes the UpdateSourceTrigger=PropertyChanged part also redundant.
Edit: about this part:
When I omit that part of the binding the model is never called when a value in the ObservableCollection changes.
Sincerely, I cannot explain myself the behavior that you've noticed (but it's quite easy to reproduce). I was expecting the binding to update viewmodel according to dependency property default UpdateSourceTrigger. But I've noticed that the ViewModel is updated not even on focus lost, but when you either move focus to next row or press enter. So the explanation that Colin Eberhardt gives in his blog seems the best I can find. Obviously this behavior is strongly related to DataGrid and if you would have the same checkbox outside of the grid, then the ViewModel would update as expected without explicit UpdateSourceTrigger set to PropertyChanged.
When you bind to a DataTable, you are actually binding to your DataTable's DefaultView, which is of type DataView. As a result, each row of your table will be bound to a DataRowView. If you look at the documentation for DataRowView you will find that it implements the IEditableObject interface which is the significant factor here. This interface allows you to perform transactional changes to your object, i.e. you can change the object's properties within a 'transaction', then commit then all in a single atomic action. By default, when you bind to a DataGrid this occurs when the user finishes editing a row, either by moving focus or hitting Enter.
Was UpdateSourceTrigger always necessary to have properties update the source?
No. The UpdateSourceTrigger property of a binding specifies what triggers the update of a source property whereas the Mode property lets you control the direction of the data flow. These are two different things.
Even if you don't explicitly set the UpdateSourceTrigger property your Hub source property will indeed still be set, but not until the you step out of the cell of the DataGrid.

MVVM not binding after initial value has been entered

I'm facing an odd issue with my WPF (MVVM) project.
I have a few controls which bind to the properties in the ViewModel. INotifyPropertyChanged is configured, everything (initially works). I type in some values into my controls and I click a button. I can see, by stepping through the code, all the property values are what they should be. So far, it is text book.
Now I notice the issue. After I click the button, some logic is performed, such as saving these values to a database. I can then edit the control values and then save to the database again. The properties at this point to do not update.
Binding clearly works, because the output shows no binding errors and when I click the Save button, the properties are correct. However, after I click the save button, and then change the property values, the properties are not updatdd. I cannot fathom why this is the case.
As a trial, I added the PropertyChanged to the update source trigger and this seems to fix the issue, however, I've never had to do this before. Any ideas what could be wrong?
I don't believe the answer is 2 way binding (I am happy to be wrong) because it binds!
<TextBox Text="{Binding DataSource, UpdateSourceTrigger=PropertyChanged}" Grid.Row ="1" Grid.Column="2" />
Where as normally I would use
<TextBox Text="{Binding DataSource}" Grid.Row ="1" Grid.Column="2" />
UpdateSourceTrigger property determines the time, when the binding has to be updated. The default value for this property is LostFocus. So by default, after you type something and move the focus out, the binding will update. If you set the property value to PropertyChanged, binding will update immediately once you entered the value in text box.
http://msdn.microsoft.com/en-us/library/system.windows.data.binding.updatesourcetrigger(v=vs.110).aspx
In your case, the binding is updated on button click, since focus transferred to Button from textbox. Once the UpdateSourceTrigger set to PropertyChanged, the binding will update on every text change.

WPF databinding after Save button click

I have an app and a Settings window with TabControl containing couple of TabItems. Each of them have some fields (textboxes) which are databinded to the same Singleton object.
Is there any elegant and WPF-like way to the the databinding only after Save button click?
Right now it's databinded immediately after changing the content of the textbox, and I want that singleton have old values and update them only after clicking the save button.
For your DataBinding object used in XAML for the Textbox, use the UpdateSourceTrigger property with value Explicit as below:
<TextBox Name="itemNameTextBox"
Text="{Binding Path=ItemName, UpdateSourceTrigger=Explicit}" />
When you set the UpdateSourceTrigger value to Explicit, the source value only changes when the application calls the UpdateSource method as below (you can put below code in Save Click event):
BindingExpression be = itemNameTextBox.GetBindingExpression(TextBox.TextProperty);
be.UpdateSource();
Instead of raising the notification of change on the set of each property (as that is what triggers the re-binding, and update), put all the raise notifications in the save button. Then when you click save, you save and tell the View to rebind to those (now set) properties.
To further this:
Bind to non singleton properties (as you want to keep the old settings until save is clicked) - without a raise notification on those properties.
In your save button, set your singleton properties, then raise all the notifications of the other properties.
In your cancel button, set your other properties to the values of the singleton properties, and raise all the notifications.
Don't forget to set your properties to the singleton properties when the view has been loaded the first time, and raise all the notifications (just like a cancel).
If you are using WPF change the UpdateSourceTrigger to LostFocus. I think that will solve the purpose.
Text="{Binding Path=MyText, UpdateSourceTrigger=LostFocus, Mode=TwoWay}"

Saving in a WPF data entry form

I have a WPF MVVM app that contains a data entry form with several text boxes. I noticed that when the user is in a textbox and makes a change that the Context object does not know a change was made until the user tabs out of that text box. Once the user tabs out of the textbox, everything works fine. But I would like to know a change was made without the user having to tab off the textbox.
Is this possible?
The way my form works is that the Save and Cancel buttons bind to ICommands. These commands have a "CanSave" and "CanCancel" method that checks to see if the EntityState changed in anyway but allowing the buttons to enable. This works great but the user has to tab off the textbox to make things work.
How can I make this work without the user tabbing off a changed textbox?
Set the binding direction (Mode) of the TextBox to be TwoWay instead of the default and set the UpdateSourceTrigger to be PropertyChanged instead of default... like so:
<TextBox x:Name="txtPersonLastname" Text="{Binding Person.LastName, Mode=TwoWay, NotifyOnValidationError=True, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}" />
(I have some additional attributes for validation in this excerpt.)
The key difference is the PropertyChanged which will update your backing property in the ViewModel. When the user types anything into the TextBox, that PropertyChanged event will fire, and in turn should trigger your CanSave, Save routines.
In Blend, it should look like this:
You have to chnage the Update Source Trigger Property to refelct the chages in your ViewModel
For Example
<TextBox Text={Binding Path=MyProperty,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}></TextBox>
Dont forget that My Property should fire Property Changed from ViweModel

Why do I get Inconsistent Binding results

I have a control template with a toggle button. This ToggleButton has it's IsChecked property one way bound to a dependancy property. If i set the dependancy property explicitly the binding works.
The problem is that after I interact with the toggle button in the UI, the bindings don't update the IsChecked property if I set the dependency property explicitly.
I do have a work arround using TwoWay binding which works fine. My question is, why does it behave this way? Am I missing something? Is there a bug in the binding mechanism of Silverlight?
EDIT TO INCLUDE SNIPPET:
The binding in the ControlTemplate looks something like (could be replaced with TemplateBinding)
<ToggleButton x:Name="PlayPause" Grid.Column="0"
IsChecked="{Binding Paused, Mode=OneWay, RelativeSource={RelativeSource TemplatedParent}}"
HorizontalAlignment="Center"
Width="50" Height="50"/>
The explicit setting of the dependency property is the fairly bog standard:
myComponent.Paused = true;
WPF deletes one way bindings when the target property (IsChecked in this case) is modified. Silverlight used to keep the binding when IsChecked was modified. If Paused was later set, this value would overwrite IsChecked as well.
According to you, it seems Silverlight reverted to WPF behavior. Oh well. Personally, I consider modifying a binded property a bug. If the properties are not meant to be in sync commanding may be a better solution.
You should use TwoWay binding
Make sure that the object that contains your Paused property supports INotifyPropertyChanged.
Make sure that the setter for Paused triggers the PropertyChanged event

Resources