wpf - Where should the crud logic be implemented in mvvm? -


in mvvm light application search in customer list. search narrows customer list displayed in master/detail view datagrid (the master customersearchresultview) , separately defined usercontrol firstname, lastname, address etc, etc (the detail - customersearchdetailview). here main content of master/detail view:

 <stackpanel minwidth="150" >         <textblock text="customer search result list" />              <grid>                 <datagrid name="customerlist" itemssource="{binding searchresult}" selecteditem="{binding selectedrow, mode=twoway}" >                       .....                 </datagrid>             </grid>             <grid grid.column="2">                 <textblock text="customer details" style="{staticresource heading2}" margin="30,-23,0,0"/>                 <content:customersearchdetail datacontext="{binding selectedrow}" />             </grid>         </grid>     </stackpanel> 

both have corresponding viewmodels. please remark dc customersearchdetail, selectedrow - property on customersearchresultviewmodel , defined this:

private customer _selectedrow; ... public customer selectedrow         {             { return _selectedrow; }             set             {                 _selectedrow = value;                 raisepropertychanged("selectedrow");             }         } ... 

because of have not defined dc on customersearchdetailview - set in binding on "master" view (as shown above) , seems work ok.

in model folder have created customer class in use here. implements observableobject , idataerrorinfo , have public properties raisepropertychanged events.

i run application , seems ok. note: viewmodel customersearchdetailview (that customersearchdetailviewmodel.cs) @ stage empty shell , not in use (as far can see ... constructor never accessed)

now want add save/update functionality customer in detail view. ok, add save button customersearchdetailview this:

<button content="save" command="{binding path = savecommand}" width="80" margin="0,0,15,0"/> 

i create "savecommand" relaycommand property in customersearchdetailviewmodel - never accessed.

hmmmmm ... after googling , forth come this:

 <button content="save" command="{binding source={staticresource mycustdetails}, path = savecommand}" width="80" margin="0,0,15,0"/> 

i defined "mycustdetails" resource in view pointing customersearchdetailviewmodel. , voila! hit method when debugging ... alas, customer of course "null". (in fact spent 2 hours implementing commandparameter here , binding "selectedrow" property on master view - customer still "null").

more googling , searching mvvm examples, , implemented "savecommand" on customer class (the model object). , guess what? edited customer got passed along - send ef layer , seems ok ....

and - if still me - here comes questions:

1.) - , thought "proper mvvm way" of doing things - have crud/repository accessing in viewmodel. how can in scenario?

2.) have crud in place via model class (customer) - should bother question 1? in fact have deleted customersearchdetailviewmodel , runs ok. feel have invented view - model (mv) framework ... :-p

i feedback on - , apologize "wall of text".

assuming dc means datacontext

just opinion:

  • first question doing special selectedrow in customersearchresultviewmodel?

if answer no, rid of property , have customsearchdetailview bind directly datagrid using {binding elementname=customerlist, path=selecteditem}

  • now save / update commands need used button's in customersearchdetailview. instantly i'd inclined using separate vm view , have these command's defined there.

now mentioned these commands not accessed. answer because in program you're never creating customersearchdetailviewmodel.

normal operation view's datacontext it's vm(if requires one. in case imo cos need hold commands)

looking @ code i'd guess using mvvm light. in viewmodellocator have main property , in main view, got datacontext set using main property , source={staticresource locator} locator viewmodellocator created in app.xaml resources. thereby creates viewmodel view defining datacontext. can ofcourse same in code-behind let's not go off topic.

so in case got datacontext set selectedrow of type customer , binding's resolved using datacontext , that's why when command's defined in customer works fine when it's in vm did not.

so why did work when had commands in vm , used

<button content="save" command="{binding source={staticresource mycustdetails}, path = savecommand}" width="80" margin="0,0,15,0"/> 

^^ worked because datacontext not used since source has been specified explicitly. , where-ever mycustdetails defined in resources, there vm got created.

so worked what's wrong that?

well it's quite big mess. mentioned customer details in vm null. hope can guess why now. it's because vm created in resources via x:key="mycustdetails" nothing in ever used or set apart when binding's referred explicitly

in system got commands refer either model plain wrong or vm created resource purpose. datacontext heavily linked "searchresults" view making not easy future extensions or layout updates.

if keep view <-> vm 1 <-> 1 relattion can avoid confusion. in summary can answer both question's together. while works, please don't let code , tweak better expansion future , comply basic guidelines.

so how that?

approach 1:

  1. in customersearchdetail view, add dependencyproperty of type customer lets call selectedcustomer.

  2. now replace datacontext="{binding selectedrow}" selectedcustomer="{binding selectedrow}" in customersearchresultview

  3. now set datacontext of customerserachdetailview it's vm similar how customerserachresultsview links it's vm(guessing through datacontext binding in xaml using viewmodellocator)

  4. now can have commands in button's of customerserachdetailview <button command="{binding savecommand}" ...

  5. finally because selectedrow no longer datacontext of customerserachdetailsview, bindings firstname, lastname, address appear stop working.

we got plenty of options address this.

first in each binding use relativesource findancestor binding pointing customerserachdetailsview , there via currentcustomer dp(dependencyproperty) created before appropriate field.

eg:

<textblock text={binding relativesource={relativesource findancestor, ancestortype={x:type local:customerdetailsview}}, path=currentcustomer.firstname}" /> 

now if have multiple properties gonna start getting annoying type. pick common ancestor(say 3 of these textblocks grouped under stackpanel) , apply it's datacontext currentcustomer element via similar binding ^^. stackpanel's children datacontext customer element in each of binding's don't have whole relativesource thing , can mention {binding path=firstname} , on.

that's it. got 2 view's own respective vm , model(customer) , each have respective tasks.

great, done? err not quite yet.

while approach 1 better started it's still "meh". better.

approach 2

mvvmlight has messenger class allow communicate between different classes in weak dependent format. need if haven't already.

so messenger?

pretty simple:

  1. in setter of selectedrow in customersearchresultsviewmodel we'll send message new incoming value customersearchdetailsviewmodel.

  2. now in customersearchresultsviewmodel we'll add property currentcustomer , assign incoming value.

  3. in customerserachdetailsview no longer create dp. means no longer set selectedrow anything(datacontext or dp) in customerserachdetailsview customersearchresultsview ( sweet less work :) )

  4. as way assign datacontext of customerserachdetailsview or way bind button.command - remain same approach 1

  5. finally actual "firstname" , binding's. currentcustomer property of customersearchdetailsviewmodel. binding how button bind's it's commands

^^ works fine cos datacontext textblock vm , property currentcustomer exists in it.


Comments

Popular posts from this blog

javascript - Count length of each class -

What design pattern is this code in Javascript? -

hadoop - Restrict secondarynamenode to be installed and run on any other node in the cluster -