wpf - Debugging: Why a data-bound section breaks off when DataContext is reapplied? -
update 2010 06 12
distilled essence out smaller sample - solution available here http://db.tt/v6r45a4
it seems problem related tab control : when data context reapplied (click button), seems works expected. bindings refresh bindings on active tab broken.
you can verify selecting tab , clicking button, you'd see controls on tab go kaput. added bunch of logging statements how friend arrived @ synopsis , fix [ set datacontext="{binding}" on tab control ]
but we're still not sure why behaves way does...
tabcontrol data context set reprotabitembug.mainviewmodel tabpage [lefttabpage] data context set reprotabitembug.leftviewmodel system.windows.data error: 40 : bindingexpression path error: 'middleprop' property not found on 'object' ''mainviewmodel' (hashcode=50608417)'. bindingexpression:path=middleprop; dataitem='mainviewmodel' (hashcode=50608417); target element 'textbox' (name='middletabtextbox'); target property 'text' (type 'string') tabpage [middletabpage] data context set reprotabitembug.middleviewmodel middle tab textbox text changed 634272638824920423 tabpage [righttabpage] data context set reprotabitembug.rightviewmodel middle tab textbox text changed
previous post (disclaimer: long post ahead... popcorn. i've spent part of day on this..)
my viewmodel composed of 3 poco subviewmodels. each subviemodel has properties bound in 3 sections mentioned above. each subviewmodel exposed standard .net get-only property (no inotifypropertychanged)
my view has 3 sections. each section has datacontext setter this..
... <tabitem x:name="_tabpageforvm2" datacontext="{binding propreturningsubvm2}"> <!-- followed ui items data-bound props inside sub-viewmodel --> </tabitem> ...
so summarize
<mainview> <!--datacontext set programmmatically instance of mainviewmodel) --> <control datacontext="{binding propreturningsubvm1}" >.. section1 .. </control> <control datacontext="{binding propreturningsubvm2}" >.. section2 .. </control> <control datacontext="{binding propreturningsubvm3}" >.. section3 .. </control> </mainview>
now here's puzzling bit. on normal startup, create instance of mainviewmodel (which has child view models passed ctor). properties in watch window confirm this.
trace.writeline("before setting datacontext"); mainview.datacontext = null; mainview.datacontext = mainviewmodel; //mainview.refresh(); trace.writeline("after setting datacontext");
everything works perfectly. due reasons beyond control, there scenario ui dismissed view still resides in memory. clear out when shown next time, create new instances of viewmodel , reapply datacontext (by calling same initialization routine before) when datacontext=mainviewmodel
set executed, see bunch of binding errors in output window. interesting bindings inside 1 tab page (a sub view model) broken. other 2 sub view models function correctly - no binding errors.
system.windows.data error: 40 : bindingexpression path error: 'rphgaugemaxscale' property not found on 'object' ''mainviewmodel' (hashcode=38546056)'. bindingexpression:path=rphgaugemaxscale; dataitem='mainviewmodel' (hashcode=38546056); target element 'gauge' (name='gaugecontrol'); target property 'maxvalue' (type 'double') system.windows.data error: 40 : bindingexpression path error: 'rphgaugemaxscale' property not found on 'object' ''mainviewmodel' (hashcode=38546056)'. bindingexpression:path=rphgaugemaxscale; dataitem='mainviewmodel' (hashcode=38546056); target element 'gauge' (name='gaugecontrol'); target property 'majortickcount' (type 'int32') ...
the properties exist on subviewmodel2, instead lookup using mainviewmodel.
next added refresh method on mainview (called after datacontext reapplied) this
_tabpageforvm2.datacontext = null; _tabpageforvm2.datacontext = mainvm.propreturningsubvm2;
and fixes problem.
what puzzles me is
- what special subvm2 ? if works first time datacontext assigned, why break second time around ?
- i set header of tabpage {binding} check bound , showns "fulltypenameofsubvm2", indicates datacontext property of tab page being set. why bindings broken?
you can download snoop or other tool shows visual tree , see there content of tabitem not visual child of tabitem, visual child of tabcontrol.
so tabitem logical child of tabitem's content , tabcontrol visual child of tabitem's content. datacontext should inherited logical parent, seems me it's inherited randomly either tabitem or tabcontrol.
the best solution can suggest move bindings content so:
<tabitem x:name="lefttabpage" header="leftmodel"> <stackpanel orientation="horizontal" datacontext="{binding left}"> <my:gauge x:name="gauge" height="200" width="200" value="{binding leftprop}"/> <viewbox height="200" width="200" > <my:gauge x:name="scaledgauge" value="{binding leftprop}"/> </viewbox> </stackpanel> </tabitem> <tabitem x:name="middletabpage" header="{binding}"> <textbox x:name="middletabtextbox" datacontext="{binding middle}" text="{binding middleprop}" /> </tabitem> <tabitem x:name="righttabpage" header="rightmodel"> <textbox datacontext="{binding right}" text="{binding rightprop}"/> </tabitem>
i think it. i'll try explain.
if second tab active(for example), middletabtextbox logical child of middletabpage , visual child of mytabcontrol (it has 2 different parents 2 different datacontexts). first tab not active , has logical child - stackpanel. when click button datacontext changes. , it's ok stackpanel - has 1 parent. middletabtextbox should do? shoult take datacontext visual or logical parent? seems logical context logical parent :) expeted behaviour, middletabtextbox gets visual child i.e. mytabcontrol. instead getting middleviewmodel mainviewmodel bunch of binding errors. don't know why wpf inherit datacontext visual parent not logical one.
Comments
Post a Comment