views:

469

answers:

2

I have a Form with a DataGridView which DataSource is a BindingSource to a table. This view will have a single row selection and a button to delete, edit the current selected row in a popup Form and a insert button that will use the same Form as well.

My question is how can I sync the pop Form with the current row?

I tryied to use the RowStateChanged event to get and store the current selected Row to be used in the Form but I coudnt. After the event I get the row that was selected before.

Other thing I dont understand yet in C# how to have a single recordSet and know wich is the current record even if its a new being inserted in a way that once in the Form all data being entered will show up at the same time in the DataGridView.

A: 

You can easily keep it in sync, but not using BindingSource.

Windows Forms data binding is built on top of a few interfaces the most important are: IList and IBindingList. The first one is just responsible for providing access to elements by their index in the list(to make it simple) the second one actually is more complicated.

IBindingList - (which is implemented by BindingSource) has methods to support:

  • change notification
  • adding new "empty" element
  • sorting
  • searching

The one that is important for you is of course change notification. Unfortunately BindingSource doesn't implement that bit of code. You may do 2 things here - either implement your version of BindingSource with change notification or try to mess with DGV and textboxes/comboboxes events to update the data.

Personally I've done the first one(I can share the code I have).

"Other thing I dont understand yet in C# how to have a single recordSet and know wich is the current record even if its a new being inserted in a way that once in the Form all data being entered will show up at the same time in the DataGridView."

Every form has a BindingContext object that keeps CurrencyManagers - one for each DataSource. That way every control bound to the same data source knows which record is current. Actually what BindingNavigator does is messing with the apropriate CurrencyManager and calling its methods. (I have no idea why it requires BindingSource instead of in the minimum IList or for full functionality IBindingList)

kubal5003
Tks kubal for the answer, but I think I understod almost nothing. I'm new to C#, and mainly work with Java and I remember to use, in the past, the VB recordsets where I could simply go back an forth with data.Now looks like C# uses a disconected recordset and changes made in the DataGridView needs to be updated 'by hand' in to the db.I'm looking for a simple way to to this, preferably using just the RAD interface, but looks like I need to learn much more and I cant see any good source about it to point to best practices. Will try to do my homework but still looking for a simple solution.
Ruben Trancoso
There are certainly circumstances in which you might want to enter into the world of `IBindingList` and `BindingContext` and `CurrencyManager`, but keeping controls synchronized with a `DataTable` is not one of them.
Robert Rossney
+1  A: 

You don't have to sync the form with the current row. That's what a BindingSource is for.

When you do simple binding to a BindingSource, then every time its current item changes, the bound controls get updated, and every time the values in the bound controls change, the underlying values in the bound item get updated. When you do complex binding (i.e. the bound control displays the BindingSource's list, not just the current item), changing Position on the BindingSource will also change the current position in the bound control, and vice versa. So in this case, you want to bind the controls on your second form using simple binding, and the DataGridView on your first using complex binding.

The only unusual thing you need to do is make sure that both forms are using the same BindingSource. When you do that, clicking on a new row in the DataGridView updates the Position on the BindingSource, and the BindingSource pushes the values from the current bound item out to all of the simply-bound controls that are bound to it.

This is easily accomplished. Assuming that Form1 is the form with the DataGridView, and Form2 is the one with the simply-bound controls, do this:

In Form1:

private BindingSource Source = new BindingSource();

Form1_Load(object sender, EventArgs e)
{
    // set Source's DataSource to your DataTable here.
    mainDataGridView.DataSource = source;
    // create DataGridView columns and their bindings here.

    Form2 f2 = new Form2();
    f2.TopMost = true;
    f2.Source = Source;
    f2.Show();
}

In Form2:

public BindingSource Source { get; set; }

public void Form2_Load(object sender, EventArgs e)
{       
    idTextBox.DataBindings.Add("Text", Source, "id");
    descriptionTextBox.DataBindings.Add("Text", Source, "description")
}
Robert Rossney
You got it, thank you very much. I did the thing and it works fine. I just dont know yet how to commit my changes and also, the test I did, the new added row just show some values from the form once its disposed but when another row is selected the values are there.
Ruben Trancoso
For the most part, changes are committed whenever `Position` changes, i.e. when the user moves to another row. You can explicitly commit pending changes to the current row by calling `EndEdit` on the `BindingSource`. (And you can roll them back by calling `CancelEdit`.)As far as adding a new row goes: when a new row is added, each column in the new row is populated with any `DefaultValue` defined in its `DataColumn`. Then it's added to the list, and any complex-bound controls are informed that the new row exists, and they display it.
Robert Rossney