WPF databinding after Save button click - wpf

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}"

Related

Cannot bind to additonal property in extended Control

I am reasonably proficient in XAML and WPF having trouble with binding to an additional control within an extended control from outside the control. Sorry, that's a real mouthful so let me explain:
I have a control that I have extended from a ComboBox and applied the template and overridden the property metadata and all that stuff and re-templated it so it looks and works as I want it to. Now, I want to add a TextBox to provide search functionality for the ComboBox which I have exposed dependency properties to determine if it is visible or not and added this to the first row of the Grid above the ItemsControl and all works fine. I have added a dependency property called IsFiltered and applied a template binding to determine if the filter is visible and from outside my control I can set this value and it all works.
However, I have added a dependency property to the extended ComboBox (MyComboBox if you like) as a string property so that I can assign a filter text property from my view model that will eventually work its way to the text box embedded within the control. The TextBox in the conrol is also bound using {TemplateBinding FilterText} dependency property, as it hooks back to my MyConboBox control and the assignment is accepted and recognised. However, while the property from my view model is set and read and interacts with the FilteText property in MyComboBox to which the TextBox inside by MyComboBox control template is also bound to, the TextBox does not trigger a change.
<TextBox
Grid.Row="0"
Margin="4"
Text="{TemplateBinding FilterText}"
BorderBrush="Red"
Visibility="{TemplateBinding IsFiltered, Converter={converters:BoolToVisibilityConverter}}"/>
Can anyone help?

WPF MVVM TextBox immidiate bound property update

I have a MVVM app, which shows a TextBox with its text bound to a viewmodel property:
Text="{Binding Path=Caption, Mode=TwoWay}
The update of 'Caption' property happens only when putting cursor to any other control. Is there a way, a good way, to have the 'Caption' property updated immediately when typing any char? I need this because my app displays a view twice, in same window - one is real 'work area', another - a 'thumbnail', in a listbox of all loaded 'work areas'. 'Work area' would show the new text correctly. A 'thumbnail' updates the textbox only when it loses cursor
For the text property, the default way to update bindings is LostFocus not PropertyChanged, you need to set this explicitly.
Text="{Binding Path=Caption, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}
Source

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.

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

Setting a property on the ViewModel from the View in WPF

I have a dependency property on my ViewModel which is the DataContext for my View. The ViewModel has no reference to the View. The property on the ViewModel is going to reference a control on the view, but I need to be able to set this property in XAML.
How is this possible? One thought I had was to develop a custom control which has a Property property and a Value property, so you could do something like this in the View to set the property on the ViewModel:
<PropertySetter Property="{Binding MyViewModelDependencyProperty}" Value="{Binding ElementName=aControlOnMyView" />
Before I went down this route, I wanted to check if there was any other approach I could take?
Thanks for the detailed reply Ray, but if I give you a bit more detail about the problem I'm trying to solve, you might get a better idea of why I mentioned the approach I did.
Basically, what I'm trying to do is set the focus to a textbox when the user hits a button. I've written an attached property which you can attach to the Button control, specify what the trigger event is (in this case the 'Click' event), and then what control to focus on. This works really nicely, and keeps everything in XAML.
However, I now have a use case where the focus should be set to an arbitrary text box from the click event on a button which is part of a toolbar. This toolbar is itself a user control which is sitting inside another user control, which is inside another user control! This toolbar needs to be reusable across various different forms, and each time, the control to set focus on after you click the button will be different per form.
That's why I had the idea of making the focus control (i.e. a textbox) a property on the view model itself (on my ViewModel base to be precise), and have the ViewModel base code (which the toolbar is bound to), set the focus to the control when the button is clicked (and the e.g. Add/Edit method is called on the ViewModel base).
In unit test land, the control to focus on property will be null, so it's .Focus() method just won't be called. So I can't see an issue there. My problem is then how you set the focus control property from XAML, which is why I had the PropertySetter idea.
I don't like the fact that the ViewModel has any reference to controls sitting on the view, but I can't see another way to achieve what I need. What if the logic that dictates whether to set focus to the control is quite complex? This would sit in the ViewModel surely? Therefore, is there any harm in the ViewModel having this UIElement property? It still knows nothing about the specific View it is bound to, it just knows that there is a control which it needs to set focus to when some action happens on the ViewModel.
My first reaction (and it's a strong one) is so say "Don't do that!" By giving your view model a reference to a part of your UI you are breaking the encapsulation that makes view models so powerful and useful.
For example, what if you want to unit test your view model or serialize it to disk? In each case the piece of your UI will not be present, because there will be no view at all. Your tests will miss coverage and your reconstitution will be incomplete.
If your view model actually needs references to UI objects and there is no better way to architect it, the best solution is to have the view model itself construct those controls it requires a reference to. Then your view can incorporate that control as the Content of a ContentPresenter via binding and provide a Style to configure the control, including a ControlTemplate to provide its content. Thusly:
public class MyViewModel
{
public ListBox SpecialControl { get; set; }
public MyViewModel()
{
SpecialControl = new ListBox();
}
}
and
<DataTemplate TargetType="{x:Type local:MyViewModel}">
<DataTemplate.Resources>
<Style TargetType="ListBox" ... />
</DataTemplate.Resources>
...
<ContentPresenter Content="{Binding SpecialControl}" />
</DataTemplate>
Other possibilities are:
Have the view model actually derive from the Control class, then override OnApplyTemplate() and use GetTemplateChild to find a template item whose name starts with "PART_"
Implement an attached property that takes a property name, finds that property in the DataContext, and sets it to the DependencyObject to which the property is attached.
Implement your PropertySetter idea
My option #2 would look like this:
<DataTemplate TargetType="{x:Type MyViewModel}">
...
<TextBox local:PropertyHelper.SetViewModelToThis="SpecialControl" />
...
</DataTemplate>
The code in the SetViewModelToThis PropertyChangedCallback would get the view model from the DataContext, reflect on it to find the "SpecialControl" property, then set it to the TextBox. Note that the implementation of SetViewModelToThis must take into account the possiblity that DataContext is not set right away, and that it maybe changed requiring the old setting to be removed and a new one made.
First of all, the DataContext of the control should be the ViewModel object and not a property of it. Second, when you TwoWay bind a property of ViewModel to your control, changes in the control's value will update (in your case, 'set') the value of ViewModel's property.

Resources