Ignoring text/value changes due to databinding - wpf

How does one ignore changes to a control when databinding occurs? I tried hooking various events like gotfocus,textchanged,and leavefocus, but if the control already has focus and the user "cancels" their changes, when I reload the record and data binding takes over, textchanged thinks the user still made the change since the focus is on that control. The call stack is empty. Are there any global data binding events like databinding starting and databinding ending? I see where I fire my OnProperyChanged but within that call, databinding does not occur. Looks like it's getting "queued" up and runs at some other point.
At one point, I was going to hook the property change events in our view model , but this means I won't detect and can't VISUALLY display the form is modified till the user leaves the control. I know, I know, I can change all my bindings so that binding occurs immediately on every character change but then this messes with some validation cases as the user hasn't finished typing in their value.
I'd really love some kind of event like TextChangedByUser that would fire whether the user used a key, clipboard, mouse clipboard, anything triggered by the user.
I just can't figure out how to distinguish between user changes and databinding changes.

I'd really love some kind of event like TextChangedByUser that would
fire whether the user used a key, clipboard, mouse clipboard, anything
triggered by the user.
I just can't figure out how to distinguish between user changes and
databinding changes.
Don't use the Text.TextChanged event to detect user input,
use the Binding.SourceUpdated event instead.
Or more general:
Don't use the DPs of your visual elements to detect user updates, use the Binding.SourceUpdated event instead.
This is a RoutedEvent.
At your binding, you have to set NotifyOnSourceUpdated = true. With help of UpdateSourceTrigger you are even able to finetune when you want to be informed.
Your xaml could be sth like this:
<Grid x:Name="LayoutRoot" Binding.SourceUpdated="LayoutRoot_SourceUpdated">
...
<TextBox>
<TextBox.Text>
<Binding NotifyOnSourceUpdated="True" Path="path" UpdateSourceTrigger="PropertyChanged" >
</Binding>
</TextBox.Text>
</Grid>
Your event could be like this:
private void LayoutRoot_SourceUpdated(object sender, DataTransferEventArgs e)
{
// called every time s.th. changed by user
}
(edited due to comment)
Why is this a valid way to detect if an input is triggered in any way by the user?
In the given example, the TextBox's DataContext 'path' property is the source, while the 'TextBox.Text' property is the target.
[Data Binding Overview]http://msdn.microsoft.com/en-us/library/ms752347.aspx
The TextBox.Text property is changed for the first time when the binding initializes and the source-value is written to the 'TextBox.Text' property. Because you do not know when the binding takes place exactly you cannot use the TextBox.Text property or any of its events (e.g. TextChanged) to detect a user input. Hence:
Don't use the Text.TextChanged event to detect user input!!! more general: Don't use the DPs of your visual elements to detect user updates!!!
If the user changes the content of the visual text field by which means whatsoever, the 'TextBox.Text' property changes (your target).After that, the binding updates the source at a time defined by UpdateSourceTrigger.That's when the SourceUpdated event is fired.
I admit not to know the effect of changes to the binding source from outside the binding.
But I have a complete Editor-like Desktop-Application detecting changes by the user that way and it is working very nicely.

You should update your Binding Code to set the following
{Binding Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
EDIT: Sorry, I have overseen the fact that you already know this...In that case, I can't help :(

You can use the UIElement.TextInput event to detect user input.
Note that the event is probably already handled by the input control itself so you might have to use the UIElement.PreviewTextInput event.

Related

Catching notifications from INotifyPropertyChanged before WPF windows close

In my current application, I have a WPF window with a large number of text fields for the user to fill in. To try and avoid loss of data, I've implemented a feature to notify users if they have unsaved changes.
The underlaying data object in the ViewModel implements INotifyPropertyChanged. So on each change I can set a boolean property on my BaseViewModel to indicate that something has changed. However, this notification only happens when the user moves off any given textbox and onto another part of the window.
The BaseViewModel also has an overridable SaveChanges method, in which the property is reset to indicate the data has been saved.
We're using MVVM, but in a nod to practicality, we do have one bit of code-behind. In the underlying view there's an assignment of a function to the Closing event. In the function, we check the boolean and give the user a messagebox to warn of unsaved changes.
This all works fine in the majority of situations. However, if someone alters text in a box and then goes straight for the close button on the WPF window, the property changed event gets fired after the window closes.
Is there any way I can catch this event and stop the window closing in this eventuality?
However, this notification only happens when the user moves off any given textbox and onto another part of the window.
You can control this using the UpdateSourceTrigger property.
<TextBox Text="{Binding Width, UpdateSourceTrigger=PropertyChanged}" Width="50" />
For a TextBox, the default value for this property is LostFocus, please refer to the Remarks section of the link.

Timepicker Updatesourcetrigger=propertychanged doesn't change value

I'm hosting a WPF usercontrol in a windows form
In the wpf user control I am using a timepicker from wpfToolkit.extended
If I use the up or downkeys or just enter a time in the textfield the source is not updated allthough I am using Updatesourcetrigger = propertychanged.
When I select a time in the dropdrownlist everything works the way it should.
This is the namespace of the toolkit.
xmlns:xctk="clr-namespace:Xceed.Wpf.Toolkit;assembly=WPFToolkit.Extended"
This is the xaml for the timepicker
<xctk:TimePicker Format="LongTime" TimeInterval="00:15:00.000" Value="{Binding Path=StartTime, UpdateSourceTrigger=PropertyChanged}" ></xctk:TimePicker>
If I click outside the WPFusercontrol without changing the focus to another control in the wpf usercontrol first. The Binded time is not updated.
Any idea how I can fix this?
Found a solution for this problem:
I've given the TimePicker a name (In this case 'tpFrom') then I've used the TextBoxBase.TextChanged event on the TimePicker.
This is what the Xaml looks like now:
<xctk:TimePicker Name="tpFrom" Format="LongTime" TextBoxBase.TextChanged="TimePicker_TextChanged" TimeInterval="00:15:00.000" Value="{Binding Path=StartTime, UpdateSourceTrigger=PropertyChanged}"></xctk:TimePicker>
In the code behind in our eventhandler we'll put the focus on our timepicker.
private void TimePicker_TextChanged(object sender, TextChangedEventArgs e)
{
tpFrom.Focus();
}
Now everytime the text changes, the value changes as well and the problem is solved :-)
Does the TimePicker have a Text property? If so, try binding to that instead.
I think this behavior might be to prevent you from binding to a bad datetime as you type. I would guess that when focus is lost it tries to set the property and does error checking. If it did this while you typed it would constantly be changing the value anytime you make a change (say delete a character).
Is there something specific you are trying to do as you type?

WPF Notify Property on a Child User Control

I have a user control UC_A that contains a user control UC_B. Each has a different view model as its data context, VM_A and VM_B respectively, both derived from INotifyPropertyChanged.
A command from VM_A changes stuff that affects a property in VM_B. UC_B has a binding to that property. How can I cause the binding to update? I tried OnPropertyChanged in VM_A but it does not do the job.
Any help would be appreciated.
If VM B changes, then the notification must be raised from there to notify UC B.
To add on what #flq said already,
I don't see what's the problem, if you implemented OnPropertyChanged properly it should just work.
i.e. when your View-model-A changes something in the view-model-B - then whatever property is changed in the VM-B should fire off the OnPropertyChanged - from the VM-B - and that'd 'land' into the UC-B lap, as it should.

wpf: TextChanged event fired on setting DataContext

I've got a simple View with a single textbox that gets databound to a simple ViewModel with a single string property.
I need to catch the TextChanged event of that textbox so that I can do a little validation magic.
The problem that I am running into is that the TextChanged event fires for that textbox when the DataContext is set for the View.
Is there a standard mechanism that I can use to determine if the event is firing because of the DataContext being set versus when the user is making changes?
Thanks!
As far as I know there is no such mechanism. What you should do instead is to do your validation magic using standard means of WPF. Please see the following link: http://msdn.microsoft.com/en-us/library/ms752347.aspx#data_validation.
Anyway, as long as you use MVVM you can always detect that text has changed in the setter of the bound property in your view model.

Update Dependency Property prior to program exit

I have created a dependency property of type Binary on a RichTextBox which allows me to bind to a FlowDocument which is in binary form (byte[]) within the ViewModel. This works well, the property converts to and back correctly.
Whenever the RichTextBox looses focus then the value of the dependency property is updated with the new binary representation of the FlowDocument.
My problem is that if I have been using the RichTextBox and I close the window, the RichTextBox does not lose focus and hence the dependency property is not updated with the new binary representation of the FlowDocument and therefore new changes are not commited to the database. In my ViewModel I have a method CleanUp which gets called when a ViewModel is getting ready to be disposed, where I can save the updated document.
How can I get the dependency property to update itself as the RichTextBox doesn't lose focus if the user clicks to close the window?
I brainstormed the following:
Tell the dependency property to update itself via a message broadcast. I am not clear on how to register a message listener within the dependency property.
Query the RichTextBox directly, get the Document, convert it to a binary object manually.
Get the view to move focus to a dummy control, so that the dependency property now updates itself.
What do you guys think?
Update: the on changed event for the dependency property adds a event handler which is waiting for the RichTextBox to loose focus. It is this handler that updates the dependency with its new value.
Use an UpdateSourceTrigger of "PropertyChanged"
Something like:
{Binding Path=MyProperty,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}
I had a similar problem once, the solution I used was to move the focus to a different control and I never had any problems with this.
In my case there were several editable controls in the window so I didn't have to use a dummy control.
What's stopping you from handling the closing/closed event of the Window and moving focus or updating the binding?

Resources