|
I have a simple database for which I've written a vb.net interface. The interface consists of a DataGridView control and a RichTextBox, both bound to a single DataView. The setup is as follows:
A DataSet that is filled with data from a database file. A DataView is then created with it's table set to the single table in the DataSet. A DataGridView is created with it's datasource set to the DataView. A RichTextBox is created and a databinding is added pointing to the DataView's last column of data.
I'm trying to have the last column of the DGV be the same as the RichTextBox--both allowing editing of the value in the last column of the dataset at any time. However, changes are not always being "detected" by the dataset and .HasChanges.
Clicking a SaveButton (effectively leaving the TextBox and checking the DS.HasChanges property) informs us that there have been no changes to the DS. If I change rows in the DGV, then the .HasChanges property seems to indicate that there are changes and all is well.
-Firstly, is there a way to avoid having to force the user the change rows in order to detect the changes? -Second, is there a way to force the dataset to believe that it has changes, essentially a manner of manually setting the (ReadOnly) property of .haschanges to true?
| | smarr Saturday, March 24, 2007 3:25 PM | Include the following statement in your SaveToDB_Click Sub, before checking for changes:
RTB.DataBindings( "Text").BindingManagerBase.EndCurrentEdit()
Andrej | | Andrej Tozon Sunday, March 25, 2007 9:15 AM | Hi,
for the first question, try calling DataGridView's EndEdit() method to post changes, made in DGV, to underlying table.
Secondly, dataset itself has changes, if any table in it has at least one row, that's been changed. To have dataset report it has changes, you can set any of included row's RowState to modified:
myDataSet.Tables[0].Rows[0].SetModified();
However, I see no point in doing this...
Andrej | | Andrej Tozon Saturday, March 24, 2007 9:51 PM | Using EndEdit in the dgv does not work (or at least, have the desired effect).
Keep in mind that I am *not* editing the grid view cell--I am editing the *RichTextBox*. The RTB is not informing the dataset that it has changes.
I attempted your suggestion of SetModified, placing it in the RTB's TextChanged event so that upon entering data into the RTB, the dataset would consider itself changed. However, this seems to result in errors of "SetAdded and SetModified can only be called on DataRows with Unchanged DataRowState." This does seem a bit contradictory, since you would think that the point of "SetModified" would be to do just that.
| | smarr Saturday, March 24, 2007 10:27 PM | Have you tried setting your RTB-DataSource binding's DataSourceUpdateMode property to OnPropertyChanged (the default is OnValidation)?
Andrej | | Andrej Tozon Saturday, March 24, 2007 10:53 PM | I just tried that. No difference in behavior.
When should the RTB be automatically updating it's datasource?
| | smarr Sunday, March 25, 2007 12:58 AM | Whenever its contents change or on validation, depends on binding setting. Can you post your code you're using for binding RTB to data source?
Andrej | | Andrej Tozon Sunday, March 25, 2007 1:16 AM | I've thinned the code out to a minimum single form example for demonstration: The following assumptions are made: An access database file of a single table, a few columns. The last column is named "Description" A DataGridView named DGV. A RichTextBox named RTB. A Button named SaveToDB
Public Class Form1 Dim DS As New DataSet
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Dim MyDBFile As String = Environment.CurrentDirectory & "\JobDatabase.mdb" 'The database file Dim TableName As String = "ShotsTable" 'The only table in the Database Dim DBConnection As New OleDb.OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;" & "Data Source=" & MyDBFile) Dim SQLCommand As String = "Select * from " & TableName Dim DA As New OleDb.OleDbDataAdapter(SQLCommand, DBConnection) 'our data adapter Dim DV As New DataView 'A dataview, for possible filtering (currently no filtering being performed).
'Fill the dataset with the data DA.Fill(DS, TableName)
'Set the dataset and bind the grid control DV.Table = DS.Tables(TableName) DGV.DataSource = DV
'Bind the RichTextBox to the dataview RTB.DataBindings.Add(New Binding("Text", DV, "Description")) ' Description is the name of the last column in the database table RTB.DataBindings.Item("Text").DataSourceUpdateMode = DataSourceUpdateMode.OnPropertyChanged End Sub
Private Sub SaveToDB_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles SaveToDB.Click Console.WriteLine(DS.HasChanges) End Sub End Class
Test Steps: 1-Select a row in the DGV. The RTB will display the data in the last column named Description). 2-Change the data in the RTB. 3-Click Save Button. The dataset.haschanges does not indicate any changes to the database. 4-Change rows in the DGV (the DGV is then updated with the RTB data. 5-Click Save Button. The dataset.haschanges now indicates the changes.
| | smarr Sunday, March 25, 2007 2:00 AM | Include the following statement in your SaveToDB_Click Sub, before checking for changes:
RTB.DataBindings( "Text").BindingManagerBase.EndCurrentEdit()
Andrej | | Andrej Tozon Sunday, March 25, 2007 9:15 AM | That appears to solve the problem. I will probably place this into the .LostFocus event of the RichTextBox.
Thank you very much for your help.
So am I to understand that the DataGridView does *not* require an .EndCurrentEdit(), but that is accomplished when you change rows; and that other controls such as RichTextBox require a manual .EndCurrentEdit to be performed before the bound dataset is able to update?
I must admit that this seems contradictory to the whole concept of binding--some controls automatically update the dataset, some don't.
| | smarr Sunday, March 25, 2007 3:22 PM | You need to somehow forcethe value, you're currently editing,to update the datasource. EndCurrentEdit() pushes that changes to the underlying datasource manualy, as does moving to another record (channging DGV's current rowor otherwise). If you would be entering data directly into DGV, you should call its EndCurrentEdit *OR* change current row to push those changes to the datasource.
There's also the BindingSource component, which encapsulates some of this behaviour for you, making things a little easier. Normally, you'd put one on your form and bind it to the datasource (dataset, datatable) and then bind DGV and other simple controls (textbox, RTB) to it. BindingSource has methods like EndEdit, MovePrevious, MoveFirst, etc. to manipulate the datasource and its binding without having to deal with bound controls directly.
Andrej | | Andrej Tozon Sunday, March 25, 2007 4:16 PM | Personally, I think it's a bug with databinding, especially if you use the new DataSourceUpdateMode.OnPropertyChanged and it still doesn't work. I'm never certain where it's going to be ok and where it's not (it doesn't seem to have anything to do with changing rows in a DataGridView ... I haven't used them much in the past and my data sometimes binds just fine), so I've gotten around it by other means.
I used to encounter problems with the .EndCurrentEdit() solution not being reliable (granted, this was in 1.1, perhaps it's better in 2.0 and maybeI should re-think how I do this inmy homegrown framework), but here's how I currently handle this:
Data in a DataRow has several different versions. First, there's the original version. Then, when it's being edited, it becomes a Proposed version and once it's done being edited it becomes the Current version. Sometimes when editing, the row is left in the Proposed state and needs to be ended.
Here's a method I *always* call before I attempt to save data:
protected virtual void CommitProposedChanges(DataSet ds)
{
if (ds == null)
return;
for (int nTable = 0; nTable < ds.Tables.Count; nTable++)
{
for (int nRow = 0; nRow < ds.Tables[nTable].Rows.Count; nRow++)
{
if (ds.Tables[nTable].Rows[nRow].HasVersion(DataRowVersion.Proposed))
{
ds.Tables[nTable].Rows[nRow].EndEdit();
}
}
}
}
| | BonnieB Sunday, March 25, 2007 4:43 PM |
|