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:
- i have
dataset
containingdatatable
values. example, there's 2 columns.id
integer
, 'selected'boolean
value. none of these evernothing
ordbnull
. - i want bind each row 1
checkbox
control. 1checkbox
perid
value.checked
property should boundselected
column indatatable
. - when changes made, , user clicks
button
, want able tell changes user made, usinghaschanges()
,getchanges()
methods ofdataset
(ie 2 rows updated if user has changedchecked
property of 2 ofcheckbox
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 modeonpropertychanged
. - handle
checkedchanged
event ofcheckbox
controls , callinvalidate
method of grid show changes in grid. - in
checkedchanged
callendedit
ofbindingsource
checkbox
bound to. - note: call
endedit
usnigbegininvoke
let processes of checking checkbox (including updating data source) completed.
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
Post a Comment