Saving in a WPF data entry form - wpf

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

Related

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.

How to make a TextBox update its source ListBox's SelectedValue (without code-behind?)

I'm learning WPF and am really trying to drill down on binding until I can do it like a boss. But I'm having a bit of an issue.
In xaml, I have a ListBox like so:
<ListBox Name="AccountsDisplay"
SelectedValuePath="Username"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Accounts}"
/>
And I have a TextBox that's pulling "Username" from said ListBox.
<TextBox Text="{Binding ElementName=AccountsDisplay, Path=SelectedValue}"/>
Note: Accounts is both an ObservableCollection and all objects added to it are of type Account, which is purely a data class that extends INotifyPropertyChanged, and has properties such as Username, Password, etc.
The TextBox is pulling the Username property properly, and updates any time I change selection in the ListBox (which is populated with pretty lil' Account info entries, as intended), but I cannot then click on the TextBox and attempt to update the Username portion of entries in the ListBox.
My gut tells me I'm going about this TextBox the wrong way, since I won't be able to make other TextBoxes and pull any additional Account properties (thanks to SelectedValuePath already having a value), but I'm too new to WPF & XAML to see where the error is in my ways!
Am I barking up the right tree, or is there a more appropriate way to get a TextBox to synchronize with (and edit) the data in another UI Element?
Consider binding to the property of the actual DataContext of the list item selected.
I do not use SelectedValue because I am not sure of it's purpose.
Because of my ignorance regarding the use of that particular property, I just rely on SelectedItem.
I can then specify the property name that I want to bind to relative to the DataContext of the selected list item.
<TextBox Text="{Binding ElementName=AccountsDisplay, Path=SelectedItem.Username}"/>

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

DataGrid , TextBox - binding and instant updates

My app. contains the window in the picture:
The ItemsSource of the DataGrid is set to _editList ( declared as IList < Vendor > _editList;).
The data grid is set to Read Only.
The Vendor Name text box has the binding set as :
Text="{Binding ElementName=dataGridVendors, Path=SelectedItem.Name, Mode=TwoWay}"
This works well. However, as it is the Vendor Name cell only updates when the user is done typing in the Vendor Name textbox and clicks on something else. Say I want to change the vendor name to "John Lennon II" . I have to click on the textbox and type the characters I want to add and than I have to click on something else and only then the datagrid makes the update.
I want to make the update happen as the user types the characters....Is this possible ?
Regards,
Sebastian
Add the UpdateSourceTrigger to your Binding
Text="{Binding ElementName=dataGridVendors, Path=SelectedItem.Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
Its default trigger is lost focus. When you change it to PropertyChanged the Updates will done when you're typing.

Force WPF to Commit Changes on Focused Element

I'm working with VS2010, WPF and EF. I've placed controls on my window by dragging an entity out of the Data Sources toolwindow. I used the "details" setting so my entity is represented by several labels and textboxes. I've also added a button with the following code:
_context.SaveChanges();
When I'm editing data, the changes in whichever textbox has focus are not committed back to the DB. Everything else commits just fine. If I shift focus to another element prior to hitting the save button, it commits as well. I've experienced the same thing with the DataGrid.
I know I'm missing something simple, but I can figure it out. Any ideas on what I'm missing?
Thanks!
This is because TextBox's default Binding UpdateSourceTrigger is LostFocus. If you modify all your Bindings to set this to PropertyChanged, it will work like you expect:
<TextBox Text="{Binding SomeProperty, UpdateSourceTrigger=PropertyChanged}" />
I just ran into this same issue when trying to set the value of a databound TextBox programmatically, but Abe's suggestion didn't work for our setup (it was causing some erratic validation behavior).
Here's how I got it to work:
TextBox tb = (TextBox)this.FindName("TargetTextBox");
tb.Text = "1234";
tb.GetBindingExpression(TextBox.TextProperty).UpdateSource();

Resources