DataGrid , TextBox - binding and instant updates - wpf

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.

Related

Trying to get the currently selected item from a ComboBox DataTemplate inside a DataGrid off an DropDownClosed Event Handler

I previously had a ListView that was displaying an ObservableCollection of "Player" object properties, which I'm trying to convert into a DataGrid. I have most of it working, but currently having some issues with seeing changes on one particular property (Status), which is represented by a ComboBox. The idea is to allow players to override the "Status" value between a set of enums representing things like "Alive, Dead, Poisoned," etc. I've hooked up an EventHandler for when the ComboBox is closed and inside that handler, try to grab the sender object as a Player so I can send out the valid player values.
Here's a snippet of the XAML where I'm creating the ComboBox via a DataTemplate.
<DataGridTemplateColumn Header="Status">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox Name="cbStatus"
ItemsSource={Binding Source={StaticResource statusTypes}}"
SelecteItem="{Binding statusType, Mode=TwoWay}"
DropDownClosed="cbStatusType_DropDownClosed"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
Inside the Event Handler, I'm using the following to try and grab an "Player" object based on the values coming back from that particular row of the GUI.
Player playerOverridden = (Player)(sender as FrameworkElement).DataContext;
However, when I'm debugging the new playerOverridden when the ComboBox closes and a new value is selected, I'm not seeing that value being captured in playerOverridden.
This is pretty much the exactly what I was doing in a ListView with GridViewColumn.CellTemplates and it was working just fine. Not sure why the Status value is coming back as whatever it was initially set to instead of what the player has selected from the ComboBox.
Had to set the UpdateSourceTrigger on the SelectedItemBinding to be PropertyChanged, it works. Not sure why this has to be set explicitly inside a DataGrid where it's not something I needed to do in the ListView.
SelectedItem={"Binding statusType, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

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

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

WPF CheckBox IsChecked can't be reset when page(data source) is updated

I have question on the checkbox.
First of all,
I have a usercontrol which has a list box like this and this user control will be switched by 2 button and then the data source is changed and then the the displayed officer status will be changed:
When I check the checkbox, Officers[0].IsOnDuty will be changed to true.
The problem is:
When I click another button and switch to another data source, this checked check box is still checked but the Officers[0].IsOnDuty for this data source is false.
How to solve this?
The data context of the list box item is an item for your officers collection, not the collection itself. And using a one way binding is incorrect, as the data source (the officer) will not be updated. So change the DataTemplate to:
<CheckBox IsChecked="{Binding Path=IsOnDuty, Mode=TwoWay}" />
*Here is the list box xaml:
<ListBox ItemsSource="{Binding OfficersCollection}">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding Path=Officers[0].IsOnDuty, Mode=OneWay}" />
*
The problem with your approach is that once you change the ItemsSource (by switching to the next page) your chekcbox is still bound to the item of the first collection. I think this happens because you explicitly use an indexer for the binding Path=Officers[0].IsOnDuty
Your samplelist box xaml does not really make sense. the ItemsSoruce is a OfficerCollection and your ItemTemplate binds to a collection of Officers too. Depending on what you are trying to accomplish you should do one of the following:
If your are just interested in the first officer (as your sample suggest), add a DependencyProperty FirstOfficer (or a INotifyPropertyChanged) property to your collection and bind to it: IsChecked="{Binding Path=Officers.FirstOfficer, Mode=OneWay}"
If you however are interested in all Officers and want checkboxes for all of them you should create a DataTemplate for the Officer type and use this as the ItemTemplate.
Generally you can stay out of a lot of trouble if you stick with MVVM and really tailor your ViewModel objects very close to what the View needs so you can bind your View to the ViewModel in the simplest possible way. Think of the ViewModel as the View you want to build but without a visual representation.

Resources