Welcome

You have reached the blog of Keith Elder. Thank you for visiting! Feel free to click the twitter icon to the right and follow me on twitter.

TIP: Managing BindingSource Position in Data Driven WinForms

Posted by Keith Elder | Posted in .Net, Programming, Smart Clients | Posted on 28-06-2006

If you are working with a Windows Form where a user can create and edit data in the same form you may run into the problem of trying to set the BindingSource to a given record in a DataSet you want to work with. 

For example let’s say you have a DataGridView in a Smart Client.  When the user double clicks a given row in the DataGridView a form opens so they can edit the data.  More times than not (no matter how many demos you watch) user’s do not edit data values in DataGridViews.  Although this is a supported feature, business objects are too complex.  Imagine having to edit a contact in a single row in Outlook for example, not fun and not very user friendly.  Why every Microsoft demo I watch shows editing in DataGridViews is beyond me.  I digress though.

When the new form is instantiated we need to pass two things:  the dataset we are working with, and the IDof the item we want to edit.  We can pass this information into the constructor of the form without any trouble as seen below. By passing in the DataSet we can add new records, delete records or whatever we need to do.  The other benefit is since the dataset is passed by reference, any changes to it will automatically appear in the row the user just double clicked on.  In order for the form fields to be auto bound to the record the user clicked on we need to set the DataBinding of the controls in the form to a BindingSource.  The BindingSource serves as the go between between the UI and data store.    Here’s a sample “CellDoubleClick” event that would happen in the DataGridView:

    1    int id = Convert.ToInt32(DataGridView.Rows[e.RowIndex].Cells[0].Value);

    2             MyForm myForm = new MyForm(dataSet, id);

    3             myForm.Show();

As the form loads the problem we face is having to tell the BindingSource in the form which record we want to set as the BindingSource.Current item.  At first glance it looks like we would just get the DataRow and then set it as the Current property.  Wrong.  The BindingSource.Current property has only a get accessor.  Instead we need to use the BindingSource.Position property.  Note:  Any change to the position property updates the current property used by the bindingsource.  The problem we face now is the BindingSource.Position property wants to know the index of the item in the underlying DataSource.  

We don’t know the index value used by the BindingSource but we do know the ID we want to use.  This is where the BindingSource.Find() method comes in.  Using the find method we can basically search the underlying datasource and retrieve the index of a given item.  Here’s an example:

contactBindingSource.Position = contactBindingSource.Find(“Id”, 2);

Once the line above runs, it is going to search the column “Id” in the DataSource associated with the BindingSource and return the index of that item. 

What if you use the same form to create a new item?  Simple, call the BindingSource.AddNew() method which will add a new item to the underlying DataSource.  Then move the index to the last item.  Here’s a sample:

      bindingSource.AddNew();
      bindingSource.MoveLast();

Since items are always added at the end of the associated data source the MoveLast() method will set the index to the last item in the underlying datasource.

I hope this makes sense because it is an easy way to have a form bound to a DataSet and use the same form to perform “CRUD” operations with.

Comments (12)

Hi there, i have created a project in vb express 2008 and have a back end database (Access 2007).  I have been trying this for almost a year and to date i cannot get this right.  On load, i want to add a new number to my quote, so it would be the current quote number +1 off course.  come as may, if i only have one document in the database, the next number will be 2.  If i have any more than that, it keeps going to the first record in the database.  I have tried movelast, movefirst, movenext, moveprevious, i have even got some odd formula’s and coding off the net, i just cant understand.  Ill snippet just a small section of my load procedure:

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

Dim quotenumber As Long

Dim Newquotenumber As Long

‘Static quotenumber As Integer

‘TODO: This line of code loads data into the ‘Stock_In_OutDataSet.Customers’ table. You can move, or remove it, as needed.

Me.CustomersTableAdapter.Fill(Me.Stock_In_OutDataSet.Customers)

‘TODO: This line of code loads data into the ‘Stock_In_OutDataSet.Stock_Take_List_Mounting’ table. You can move, or remove it, as needed.

Me.Stock_Take_List_MountingTableAdapter.Fill(Me.Stock_In_OutDataSet.Stock_Take_List_Mounting)

‘TODO: This line of code loads data into the ‘Stock_In_OutDataSet.Plates’ table. You can move, or remove it, as needed.

Me.PlatesTableAdapter.Fill(Me.Stock_In_OutDataSet.Plates)

‘TODO: This line of code loads data into the ‘Stock_In_OutDataSet.REP_QUOTE’ table. You can move, or remove it, as needed.

Me.REP_QUOTETableAdapter.Fill(Me.Stock_In_OutDataSet.REP_QUOTE) ‘count0

quotenumber = QUOTE_NUMBERTextBox.Text

quotenumber = QUOTE_NUMBERTextBox.Text
quotenumber = QUOTE_NUMBERTextBox.Text
’10

Me.REP_QUOTEBindingSource.AddNew()

Me.REP_QUOTEBindingSource.MoveLast()

Newquotenumber = quotenumber + 1
QUOTE_NUMBERTextBox.Text = Newquotenumber.ToString(

Newquotenumber = quotenumber + 1

QUOTE_NUMBERTextBox.Text = Newquotenumber.ToString(
“D7”)

End Sub

Any help would be SOOOOOO much appreciated!

Any help would be SOOOOOO much appreciated!

It is great, thanks, but is it possible to get a dataview[] or dattableview containing only the records filtred by the relation?
I have an address book table and a related Documens table with relation in typedDataset. the datagrid for documents shows the selected address book records related document. ( adb id = 1 has 3 doc) (in document table I have 20 rows).
The position in the binding source return 2 (I am on the second line) I want to get the row in new DataRow dr1 using the adb_dataset.DocumentTable.rows[docBindingSource.position] I got the second row in document table and not the second row in from related document.
How can I get the the displayed row in a dataRow var? in preference without using the find method, It should have a way to get only the 3 related documents rows in a datarow array or a tableview?

@abc

I’m not sure why you are getting a boolean as a return when the API documents it returning this:

public int Find(
string propertyName,
Object key
)

Which is an int.

contactBindingSource.Position = contactBindingSource.Find(“Id”, 2)

does this statement return the index of the found item?…. when ive tried to show it using the messagebox, the system returns true or false instead of index number…

can u help me with this?..tnx

Data updation failure
Code Used
Private Sub NamesBindingNavigatorSaveItem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NamesBindingNavigatorSaveItem.Click
Try
Me.Validate()

Me.NamesBindingSource.EndEdit()

Catch sqlEx As Exception

MsgBox(“Edit FAILED “)

End Try

Try
Me.NamesTableAdapter.Update(TestDataSet.Names)

MsgBox(“Update successful”)
Catch ex As Exception
MsgBox(“Update failed”)
End Try

End Sub

Any help gratly appreciated!

Is there any way to use de find property of BindingSource to find Compound Key?
Thanks For Your help

Man thanks,

I worked for 2 hours until I saw your post and noticed that you call MoveLast() After AddNew

Nice 🙂

Thanks for the hint with using movelast after adding new record.

Elder, I appreciate you reply but my scenario is to bind selected row to another form, where i can either edit selected row or add new data and then save. how can achieve this using the binding source or your approach

To bind the values to a text box the easiest way if you are using a dataset is to use a strong typed dataset generated from your database directly. At the top of VS click on Data and then add a datasource. Select “Database”, drag over the tables you want, then in the data viewer, drag over the properties from the datatable onto the designer and it’ll bind them up for you. There are some videos out there that show this, just search around, it is really easy once you see it done.

that was great! I have searching for that piece of info for long because i am a new bie in C#. pls can you give me a fuller or complete code in terms of binding those values to text boxes , editing and saving back to the database.

Your are highly appreciated.
Thanks a billion

Thank you, Elder! That’s JUST what I needed to put the MASSES of information in perspective.

Wisdom indeed!

See date is June, 2006 — this is INDEED the gift that keeps on giving!

Write a comment