DataGridViewCheckboxColumn not setting underlying data - winforms

I have a DGV bound to an IEnumerable. T has a boolean property which can be get/set. When loading the table, the get property is accessed to populate the DataGridViewCheckboxColumn. I can see it being hit in the debugger. When I click a cell in the checkbox column, the checkbox is checked as you'd expect, but the underlying data source isnt' updated, and the property setter isn't called. The checkbox column has the ReadOnly property set to false.
How can I get this to update the underlying bound data?
polygonListBindingSource.DataSource = m_displayPolygons.OrderBy(p => p.Name);
I've seen related questions, but they're not consistant in their answers. Some suggest calling EndEdit on the DGV, other suggest calling it on the binding source. Do I really have to subscribe to an event for when the cell value is changed to actually commit the change to the underlying data type? This seems unnatural.

This is down to the fact that the DataGridView only commits its edits when the current cell loses focus. Clicking on the checkbox isn't enough to commit the edit.
The standard was to do this is to use events, usually the CurrentCellDirtyStateChanged event:
void dataGridView1_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dataGridView1.IsCurrentCellDirty)
{
dataGridView1.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
It is a bit unnatural but is by design - this way your data source doesn't get flooded by edits that may not be final. Not necessarily such a big deal for a checkbox but a worthwhile design decision for the text box cell.

Related

Databound textbox updates do not persist to db

I have a winforms app with a group of text boxes for an entity, let's call the entity Product
One of my textboxes is hidden because it holds a foreign key to another database object Business Unit. I populate the hidden textbox using a combobox that looks up values on the parent table. When the selection changes, so does the value in the hidden textbox.
private void businessUnitComboBox_SelectionChangeCommitted(object sender, EventArgs e)
{
this.businessUnitIdTextBox.Text = this.businessUnitComboBox.SelectedValue.ToString();
this.businessUnitComboBox.Focus();
}
Problem is after calling SaveChanges on my context, this change on the hidden textbox is not persisted. Oddly, if I update any of the other Product textboxes, they save just fine.
The textboxes were added to the project with standard drag and drag drop from Visual Studio's GUI, and a bindingsource was created when adding automatically.
My entities implement INotifyPropertyChanged using fody-propertychanged.
I am struggling to find the issue here. Creating new records works fine, but updating that one Foreign Key value never has.
Is this because it is a navigation property and needs to be handled differently, or are there other possibilities as to why the changes are not persisted? Any help is much appreciated.
May be it is because of lacking of this.Validate() in your Save method.
Put this code in save method of your form.
this.Validate();
this.yourBindingSource.EndEdit();
yourDbContext.SaveChanges();
The default behavior of data binding is OnValidation.
To change this behavior you can go to your textbox properties, open databinding part, open advanced, Change Data Source Update Mode to OnPropertyChanged.
So the code of your databinding in designer generated codes will be like this:
this.nameTextBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.productBindingSource, "Category.Name", true, System.Windows.Forms.DataSourceUpdateMode.OnPropertyChanged));
In this case you don't need to use this.Validate before saving changes and you can simply use
this.yourBindingSource.EndEdit();
yourDbContext.SaveChanges();

Validating DataGrid data when bound directly to a DataTable - C#/WPF

I have a DataTable which I bind to a DataGrid in WPF. No column generation is done in the XAML, everything is done when I create the DataTable in code.
I have 2 way binding, so the user can update the values in the DataGrid and it will update the DataTable, although this is not an event I can see when debugging, my results show it works as intended.
However if the type of a column is say double and the user enters text, the existing DataTable data for that cell is preserved, the cell is outlined in red and my debugger output shows a FormatException occurred.
What I am wanting to do is be able to either:
a) Handle this exception and show a warning to the user in my UI
b) Have some custom validation method which can set a flag in my code that I can use to handle the error at some point
I don't mind which solution I go with, I just don't want the user to not notice the error.
Thanks.
if you wanna stay with ado.net and datatables then: http://msdn.microsoft.com/en-us/library/1120xds5.aspx
EDIT:
this.MyTable.ColumnChanging += MyTableColumnChangingStuff;
private void MyTableColumnChangingStuff(object sender, DataColumnChangeEventArgs e)
{
if(e.Column.ColumnName == "MyColumnTestName")
{
var errormsg = MyValidateTestNameMethod(e.ProposedValue);
e.Row.SetColumnError(e.Column.ColumnName, errormsg);
}
//...
}
EDIT 2:
Thanks, just given that a try and while the event does get called when
I modify my data of the correct type, it does not get called if the
datatype the user inputs is wrong. The same as before happens, the box
is highlighted red and the format exception is handled by wpf, but the
event isn't called.
thats true. and there are just 2 solution for me. first create behaviors for your input controls where you can make sure that the values ALWAYS convertible to your underlying type. another solution would be thats your viewmodel where you bind to just have properties of type string. the nice thing with this is - that you never get a bindingexception because of casting a type. and what you have to do now is to implement IDataErrorInfo where you check your string property. and of course you have to cast your string values to the right type when you go to your model.
till now i use the first approach because i use datepicker, numeric behaviors and dont have any other types.

Detecting a BindingSource SortChanged Event in order to implement 2 way binding in winforms

I am trying to write a 2 way binding application using C# winforms
I have a BindingNavigator and a DataGridView bound to the same data source
So that I can have 2 way binding ( yes in winforms ) I want to be able to detect when the bindingSource sort order has changed.
When I click the column header of the DataGridView the sort order of the grid does change
and the BindingSource.ListChanged event does fire
However the bindingSource.Sort remains null
When the grid column header is clicked the BindingSource.ListChanged event does fire
private void bindingSource_ListChanged(object sender, ListChangedEventArgs e)
{
if (e.ListChangedType == ListChangedType.Reset)
{
if (bindingSource.Sort != null)
{
controller.Sort = bindingSource.Sort; // never gets here. Why?
}
}
}
Why isn't clicking the DataGridView Column header setting the bindingSource.Sort property?
What event should I be listening to in order to detect that the bindingSource sort has changed?
Having come across this problem (for a different reason as in multi column sorting) I found it amazing that the Bindingsource doesn't have a sort changed event nor that the Datagridview's own Sorted event doesn't fire with it (it just seems to fire when it does the sorting).
The datagridview "knows" and even changes its sort glyph position.
The way I solved this won't suit most because it is specific to the task I am coding. Within my multi column sort routine I keep track of the bindingsource.sort string and then on a regular event within the Datagridview (currently trying SelectionChanged) I compare my sort string with the current Bindingsource one and switch off my multi-column sort indicators when it is different. This is ok for me because all my Datagrids are based on a common custom control.
The only other way I thought of would be to create a custom control based upon the Bindingsource and add a sort method (that calls the bindingsource sort method) and then trigger my own event. This would be fine if starting out on a new project but changing a large program becomes a pain.
It is sad given that I made a custom control from the start for every UI control (Winforms) but never thought to make a general one for Data Access.
Hope this helps someone facing the same issues.

MVVM WPF datagrid data entry problem

I have a datagrid in my MVVM application which, because of the way the client wants the data displayed, needs use template columns. They want some typical data-entry functionality though (pressing enter performs data checking, commits the row if valid, focuses on the first textbox of the next row; pressing tab focuses the next textbox...). Also, data is often imported from an external source into the grid, usually thousands of records at a time.
Right now, I have a Loaded event hooked up to each textbox which I am using to set focus after new rows are added. My problem is that the grid goes haywire when I import a lot of rows. As the user scrolls, the Loaded events are fired, and the grid becomes basically unusable. I disabled virtualization to prevent this, and find my grid taking up a gig of RAM in certain configurations, which is unacceptable. I can't figure out a way to get this grid to work the way they require without using a huge amount of memory. It seems as if I just need to be able to focus a textbox within a newly added row, but since the data validation is performed in the viewmodel, I don't have access to the new row in codebehind, so I can't just call "newtextbox.focus()" or whatever. I'm getting pretty desperate here, any suggestions would be massively appreciated.
Put an event listener in the code behind that can call your newtextbox.focus() (and whatever else you want to do). In the validation in the view model, fire the event with args that indicate what you want your grid to do.
Edit: OK, new approach. Try trapping the keystrokes, and on enter or tab do the things you want it to do.
This would be in your xaml
<Grid KeyUp="myDataGrid_KeyUp" >
This would go in your code-behind
private void myDataGrid_KeyUp(object sender, KeyEventArgs e)
{
if (e.Key == Key.Enter)
{
// do your enter stuff here, manipulate the view model for validation, etc.
}
else if (e.Key == Key.Tab)
{
// do your tab stuff here (get selected row, determine cell focus, focus on next cell)
}
}

Silverlight Twoway Binding and rolling back changes - how to?

I have simple SL user control. A listbox which shows all customers and on the right a number of textboxes and comboboxes that are bound to the SelectedItem (Customer) in the listbox. The SelectedItem bound to SelectedCustomer property.
I am looking for a pattern/methodology to deal with canceling changes made to the customer (in the bound textboxes and combo boxes).
The edit controls (textboxes and combo's) can be one or two way bound to the selecteditem of the listbox.
If they are two way bound, immediate changes in the textboxes are reflected in the listbox. If they are oneway bound the changes in the textboxes are not reflected in the SelectedCustomer object.
At the bottom of the edit form i have typical Save, Cancel, Delete buttons. The save button for instance would take the SelectedCustomer object (if twoway bound and I would send through service for saving on server).
If the textboxes are one way bound i have to capture somehow the textbox values and insert into some object for sending to the server for saving.
If I use twoway binding , and say the save operation fails...i have to set the SelectedCustomer values back to original values otherwise the client now continues to see data that has not been saved.
There must be an easy way of dealing with this type of scenario....
RIA Services with Entity Framework already provides this functionality, basically how RIA services works and you can do it too as follow.
Each class implements interface called IEditableObject, which provides methods BeginEdit/EndEdit and CancelEdit. And it also stores (copies) instance of same class with name "OriginalEntity" with same values that were loaded from server.
After the form shows up for user to modify, BeginEdit is called, which probably caches every property using reflection, in some sort of dictionary. If you call CancelEdit, then values from OriginalEntity are loaded back in object.
Upon some errors while saving changes, you can either refresh the entities from server (best way) or you can try loading properties back from OringalEntity property.
I wouldn't discard user changes, as that easily leads to user frustration. IMHO, the user should not be informed about connection problems by uncontrolled data rollbacks.

Resources