vb.net - Databinding one control per row in the same datasource -


i've been trying deal frustrating issue regards databinding in winforms.

i have data source, datatable in dataset. datatable has 3 rows. have 3 checkbox controls on form, , button. want bind each checkbox 1 row in data source, , have data source reflect value in checked property whenever checkbox updated. want these changes correctly picked calls haschanges() , calls getchanges().

when button clicked, endcurrentedit() called , passed data-source bound to, , dataset checked changes using haschanges() method.

however, in attempts this, encounter 1 of 2 scenarios after call endcurrentedit().

in first scenario, first checkbox has changes detected. in second scenario, other checkboxes updated value of checkbox last checked on call endcurrentedit().

in looking @ rowstate values after call endcurrentedit(), in scenario 1, first row ever has state of modified. in scenario 2, third row ever has state of modified. scenario 2, doesn't matter whether user updated third checkbox or not.

to demonstrate problem, have created simple example demonstrates it.

it's stock windows form containing 3 checkbox controls , button control, default names.

option strict on option explicit on  public class form1      public ds dataset      public sub new()          ' call required designer.         initializecomponent()          ' add initialization after initializecomponent() call.          ds = new dataset()         dim dt new datatable()          dt.columns.add("id", gettype(integer))         dt.columns.add("selected", gettype(boolean))          dt.rows.add(1, false)         dt.rows.add(2, false)         dt.rows.add(3, false)          dt.tablename = "table1"          ds.tables.add(dt)          ds.acceptchanges()          integer = 1 3              dim bs new bindingsource()              'after call me.bindingcontext(ds.tables("table1")).endcurrentedit() there 2 scenarios:             'scenario 1 - changes first checkbox detected.             'scenario 2 - when checkbox checked, become checked.              'uncomment first , comment out second see scenario 1.             'uncomment second , comment out first see scenario 2.             'bs.datasource = new dataview(ds.tables("table1")) 'scenario 1             bs.datasource = ds.tables("table1") 'scenario 2             bs.filter = "id=" &              dim db new binding("checked", bs, "selected")             db.datasourceupdatemode = datasourceupdatemode.onpropertychanged              if = 1                 checkbox1.databindings.add(db)             elseif = 2                 checkbox2.databindings.add(db)             elseif = 3                 checkbox3.databindings.add(db)             end if         next     end sub       private sub button1_click( sender object,  e eventargs) handles button1.click         me.bindingcontext(ds.tables("table1")).endcurrentedit()          if ds.haschanges()             messagebox.show("number of rows changed: " & ds.getchanges().tables("table1").rows.count)             ds.acceptchanges()         end if     end sub end class 

i've done lot of searching haven't been able work out what's happening, , @ complete loss. feels i'm trying pretty simple, suspect must have misunderstood somewhere or missed important regards binding process.

edit

it's in second paragraph, make clear, here basic outline of i'm trying do:

  1. i have dataset containing datatable values. example, there's 2 columns. id integer, 'selected' boolean value. none of these ever nothing or dbnull.
  2. i want bind each row 1 checkbox control. 1 checkbox per id value. checked property should bound selected column in datatable.
  3. when changes made, , user clicks button, want able tell changes user made, using haschanges() , getchanges() methods of dataset (ie 2 rows updated if user has changed checked property of 2 of checkbox controls).

edit 2

thanks @rezaaghaei have come solution. have refined code example of problem, , made controls generate based on data (and position accordingly) make example simple copy-and-paste. also, uses rowfilter on dataview, rather position property of bindingsource.

option strict on option explicit on  public class form1      public ds dataset      private sub form1_load( sender object,  e eventargs) handles mybase.load         ds = new dataset()         dim dt new datatable()          dt.columns.add("id", gettype(integer))         dt.columns.add("selected", gettype(boolean))          dt.rows.add(1, false)         dt.rows.add(2, false)         dt.rows.add(3, false)          dt.tablename = "table1"         ds.tables.add(dt)         ds.acceptchanges()          addhandler dt.columnchanged,    sub(sender2 object, e2 datacolumnchangeeventargs)                                             e2.row.endedit()                                         end sub          integer = 0 dt.rows.count-1             dim cb new checkbox() {.text = "checkbox" & i+1, .location = new point(10, 25 * (i))}              dim dv new dataview(dt)             dv.rowfilter =  "id=" & directcast(dt.rows(i)(0), integer)              dim bs new bindingsource(dv, nothing)             dim db new binding("checked", bs, "selected")              db.datasourceupdatemode = datasourceupdatemode.onpropertychanged             cb.databindings.add(db)              me.controls.add(cb)         next          dim btn new button()         btn.location = new point(10, 30 * dt.rows.count)         btn.text = "submit"         addhandler btn.click, addressof button1_click         me.controls.add(btn)     end sub       private sub button1_click( sender object,  e eventargs)          'me.bindingcontext(ds.tables("table1")).endcurrentedit() 'doesn't cut mustard!          if ds.haschanges()             messagebox.show("number of rows changed: " & ds.getchanges().tables("table1").rows.count)             ds.acceptchanges()         else             messagebox.show("number of rows changed: 0")         end if     end sub  end class 

the key call endedit() in columnchanged event datatable (a general call endcurrentedit() doesn't appear cut it), although 1 additional problem encountered code won't work if it's in form's new() method, if it's after call initializecomponent(). i'm guessing because there's initialisation winforms after call new() necessary data binding work properly.

i hope example saves others time spent looking this.

consider these corrections , problem solved:

  • to bind control specific index of list, bind control binding source containing list, , set position of binding source specifixindex.
  • when adding data-binding checkbox controls, set update mode onpropertychanged.
  • handle checkedchanged event of checkbox controls , call invalidate method of grid show changes in grid.
  • in checkedchanged call endedit of bindingsource checkbox bound to.
  • note: call endedit usnig begininvoke let processes of checking checkbox (including updating data source) completed.

enter image description here

c# example

datatable dt = new datatable(); private void form3_load(object sender, eventargs e) {     dt.columns.add("id");     dt.columns.add("selected", typeof(bool));     dt.rows.add("1", true);     dt.rows.add("2", false);     dt.rows.add("3", true);     this.datagridview1.datasource = dt;     var chekboxes = new checkbox[] { checkbox1, checkbox2, checkbox3 };     (int = 0; < dt.rows.count; i++)     {         var bs = new bindingsource(dt, null);         chekboxes[i].databindings.add("checked", bs, "selected",             true, datasourceupdatemode.onpropertychanged);         chekboxes[i].checkedchanged += (obj, arg) =>         {             this.datagridview1.invalidate();             var c = (checkbox)obj;             var b = (bindingsource)(c.databindings[0].datasource);             this.begininvoke(()=>{b.endedit();});         };         bs.position = i;     } } 

vb example

dim dt datatable = new datatable() private sub form1_load(byval sender system.object, byval e system.eventargs) _ handles mybase.load     dt.columns.add("id")     dt.columns.add("selected", gettype(boolean))     dt.rows.add("1", true)     dt.rows.add("2", false)     dt.rows.add("3", true)     dt.acceptchanges()     me.datagridview1.datasource = dt     dim chekboxes = new checkbox() {checkbox1, checkbox2, checkbox3}     = 0 dt.rows.count - 1         dim bs = new bindingsource(dt, nothing)         chekboxes(i).databindings.add("checked", bs, "selected", _             true, datasourceupdatemode.onpropertychanged)         addhandler chekboxes(i).checkedchanged, _              sub(obj, arg)                  me.datagridview1.invalidate()                  dim c = directcast(obj, checkbox)                  dim b = directcast(c.databindings(0).datasource, bindingsource)                  me.begininvoke(sub() b.endedit())              end sub         bs.position =     next end sub 

Comments