Best practice for using CSLA.NET with MVVM pattern

Best practice for using CSLA.NET with MVVM pattern

Old forum URL: forums.lhotka.net/forums/t/8575.aspx


Lennon posted on Wednesday, February 24, 2010

Hi, I'm using CSLA.NET to create our business objects within a WPF composite application.  I am using the Prism DelegateCommands to create a SaveCommand which is set on a WPF Button.  The ViewModel (a custom class derived from CSLA's ViewModel<T> class) is passed to the SaveCommand as a CommandParameter. 

When you click the Save button, the SaveCommand Execute method is fired, passed the instance of the ViewModel (bound to the view as the DataContext), and that contains a Save method which fires the CSLA.NET DoSave method to save the business object.

This works fine. 

The next step is to disable the Save button if the business object is not valid.  The DelegateCommand has a CanExecute method, which checks the CanSave property on the ViewModel.  However, I now need to have this CanExecute method called each time the business object's values change.  i.e. when the user types a name in the Surname text box for example, the business object raises the CanExecuteChanged, so that the Save button calls the CanExecute method again to check the CanSave property.  So that if the Surname does not satisfy all of the validation rules for that property, then the Save button is disabled.

What is the recommended approach for this?

Are there any samples for CSLA.NET/MVVM, where Prism DelegateCommands are used to save the business object via a ViewModel?

sergeyb replied on Wednesday, February 24, 2010

There is a project in Samples (under CSLA Light) that demonstrates that approach.  I think I called it RoodexUsingPrism. 

RockfordLhotka replied on Wednesday, February 24, 2010

You may want to create your viewmodel by inheriting from ViewModelBase<T> instead of ViewModel<T>.

ViewModelBase has no public methods, with the idea that you'll create the public methods that work with your particular UI framework.

ViewModel has public methods, designed specifically to work with the CSLA InvokeMethod/Execute and TriggerAction components.

Lennon replied on Friday, February 26, 2010

Thanks, that sample is very useful, and I'm now inheriting from ViewModelBase<T> rather than ViewModel<T>.

However, looking at the sample there are still two points I'm not sure about:

1) The ViewModel in the sample takes a reference to the View.  Is this a recommended approach, the ViewModel knowing about the View?

2) The commands (SaveCommand etc) sit on the ViewModel class.  This is fine for binding a Save button on the View whose DataContext is the ViewModel.  However, what would you do in the case of e.g. a File menu, where the MenuItem needs to also be bound to the SaveCommand.  It's DataContext might not necessarily be the ViewModel which is currently displayed.

sergeyb replied on Friday, February 26, 2010

1) Something somewhere has to marry VM and V.  You can write a separate class, use module (which has limitations) or have View do that (eitehr via XAML or in constructor).  All of these appraches are valid, IMHO, alebeit you will find many people who would think otherwise.

2)  Chances are you will have to have a basic VM that has more flexibility and less functioanlity than VM Base for those one-off cases.

 

RockfordLhotka replied on Friday, February 26, 2010

Lennon

1) The ViewModel in the sample takes a reference to the View.  Is this a recommended approach, the ViewModel knowing about the View?

Ideally the answer is no. In fact, the viewmodel should use absolutely no XAML or view types. This turns out to be hard to accomplish without creating some other UI framework elements however. In particular, you need to abstract the "shell" and define all its actions (like creating a view, linking the view to a new viewmodel and showing the view) in an interface. Then have a runtime provider that implements that interface.

It isn't a huge amount of work, but it is certainly something you have to do if you want to really get the value (testability) out of MVVM.

Lennon

2) The commands (SaveCommand etc) sit on the ViewModel class.  This is fine for binding a Save button on the View whose DataContext is the ViewModel.  However, what would you do in the case of e.g. a File menu, where the MenuItem needs to also be bound to the SaveCommand.  It's DataContext might not necessarily be the ViewModel which is currently displayed.

For my part I've given up on commanding. It isn't a powerful enough model to handle MVVM. What is really needed as a message routing component that integrates with the shell provider to route messages to the appropriate target, even outside the current visual tree. I don't have a complete answer for how this would be done (I've implemented the shell provider concept, but not this message router concept).

I thought though, that Prism had a much more powerful commanding implementation that was supposed to address this?

Lennon replied on Friday, February 26, 2010

Hi Rocky,

Prism offers an implementation of ICommand called DelegateCommand which allows the Execute and CanExecute handlers of the command to sit outside of the visual tree.  These can be placed in a static class within an assembly referenced by both the shell and the module which contains the ViewModel.  However, these handlers need to have access to the current ViewModel.  The only way I can see to solve the problem is:

1) Set the DataContext of the main menu to be the currently active ViewModel (initiated through the Prism EventAggregator)

2) Pass the currently active ViewModel as a CommandParameter.  However, as far as I can see this would need to be a custom interface which defines the same contract as ViewModelBase<T>

I've also looked into InvokeMethod/Execute, but how would you handle enabling/disabling the Save button based on the state of the business object?

RockfordLhotka replied on Friday, February 26, 2010

Lennon

I've also looked into InvokeMethod/Execute, but how would you handle enabling/disabling the Save button based on the state of the business object?

I haven't looked at Prism in any depth, so I can't help you there.

In terms of altering the UI based on the state of the business object, ViewModelBase exposes a set of public properties designed specifically to enable this scenario. For example, you can bind any UI element to the CanSave property to have it enable/disable, or appear/disappear or whatever.

The commanding approach of automatic enable/disable is convenient, but turns out to be extremely limiting when you start reimagining the user experience. There are so many other things you might want to do beyond just enable/disable that are possible by supporting broader binding to properties - so that's the direction I've been going with all my controls over the past several months.

tmg4340 replied on Friday, February 26, 2010

RockfordLhotka

For my part I've given up on commanding. It isn't a powerful enough model to handle MVVM. What is really needed as a message routing component that integrates with the shell provider to route messages to the appropriate target, even outside the current visual tree. I don't have a complete answer for how this would be done (I've implemented the shell provider concept, but not this message router concept).

I'm not a WPF/XAML/SL expert, but I'm curious - if you've "given up" on commanding, what are you doing?  There's a whole infrastructure that's built around commanding, and while I know its shortcomings, building some sort of replacement sounds like an awful lot of work...
- Scott

RockfordLhotka replied on Friday, February 26, 2010

Well commanding doesn't exist in SL, so there's absolutely no infrastructure built around it there. And everything I'm doing is either in SL or is in SL and WPF - so things that don't work or exist in SL aren't terribly useful.

And really, commanding itself was designed to solve one problem: having a button, a toolbar button and a menu item all wire up to one action. It wasn't designed to solve the broader issue of routing an event to a viewmodel for MVVM.

In fact, commanding normally can't target a resource at all - you have to use an explicit command target to get it to do such a thing, and that starts to diminish its value even in the original scenario for which it was designed.

For MVVM what's needed is something that is triggered off an arbitrary UI event, and invokes an arbitrary method on your viewmodel (which is usually a resource, and your DataContext). I've now implemented three solutions: InvokeMethod, Execute and TriggerAction.

Of the three, right now my favorite is TriggerAction, because it works with the VS10 designer, while the other two solutions don't. Specifically, only TriggerAction can be dragged off the Toolbox and have its properties set in the Properties window. The other two solutions work great in VS10 - but you have to manually type XAML.

But of course, as I said earlier, what's really needed for a UI framework (which CSLA is not) is something like TriggerAction that doesn't directly call a method on the viewmodel, but instead routes a message through the UI framework's message router infrastructure. That infrastructure should not work on the visual tree as much as on your viewmodel object model, because you don't want the message routed to a view, you want it routed to a viewmodel.

RockfordLhotka replied on Tuesday, March 02, 2010

Elements of some of the videos might be considered "obsolete" because they show how to use the CslaDataProvider. But the vast majority of the content doesn't focus on specific UI data binding concepts as much as on constructing objects, using the data portal, implementing data access and authentication/authorization - none of which is affected by the UI design pattern you choose.

The Xaml video I'm organizing (and planning now for the end of March or early April) is just going to be one video - it won't rehash all the content from the other video series. In fact, I'll assume the viewer already understands the basics of using Silverlight (and WPF), n-tier architecture options, object stereotypes, data access, data portal and security - which means the video can focus completely on Xaml binding concepts.

Regarding abandoning CslaDataProvider, I think I've been talked into keeping it around until version 4.1 to give people time to transition off that model. It isn't like it is me that decided it isn't the way to go btw, it is that Microsoft isn't using, showing or supporting it in new tools, content, etc. I would be irresponsible if I suggested the data provider model was a good move for the future, when clearly Microsoft is not pursuing that approach.

Lennon replied on Tuesday, March 02, 2010

I've decided to explore the InvokeMethod route, as WPF commands do seem too limited in scope.  On a (slightly related) topic, is there any support for passing multiple parameters to a method on the ViewModel, or is a multibinding approach the only way forward?  e.g. for a Search method on the ViewModel which takes 3 separate parameters (from 3 separate TextBoxes) on the View.

RockfordLhotka replied on Tuesday, March 02, 2010

The typical/ideal approach is to have zero parameters passed to the vm method, though that's not always practical.

But in general, your vm should define three properties (typically dependencyproperty) that the Xaml binds to from each textbox. So as each textbox is altered, the vm's properties get updated. Or in other words, the vm always knows the current state of the data.

Then the verb method in the vm needs no parameters, because it can just use the three properties defined in the vm, because they have the correct values.

Of course what's cool about this, is that the verb can alter those values and the changes appear in the UI automatically. The bi-directional nature of this approach is where the power lies.

My viewmodels often have not only the three string properties, but a set of various bool properties so the UI can turn elements on/off, or hide them or whatever - all through binding.

lukky replied on Tuesday, March 02, 2010

Rocky,

If you're "pushing" some of those properties to the VM, aren't you defeating the rich model that CSLA offers ? Or are you refering to his particular use case with his 3 textboxes used as search/filter criterias ? In such case, then they wouldn't really be part of the BO, so having them on the VM sounds logical.

Am I reading you right that you're not advocating pushing BO properties to the VM, but only adding properties, not already on the BO, needed to provide the "glue" for VM verbs ?

Thanks

 

RockfordLhotka replied on Tuesday, March 02, 2010

The ViewModelBase and ViewModel classes have a Model property, which exposes the business object to the view for binding. With a rich model like you get with CSLA objects, you absolutely want to bind the business object directly to the Xaml.

But you almost always have a bunch of other UI-specific triggers and metastate that isn't (shouldn't) be part of your model - and those would be properties of the vm.

RockfordLhotka replied on Wednesday, March 03, 2010

Yes Dan, I still hold that black-and-white distinction between UI and business layer as a primary architectural concern.

And I haven't found any greater conflict in this area when using MVVM as compared to using MVC or code-behind models.

There's always the temptation to slip logic (especially validation) into the viewmodel/controller/presenter/code-behind/javascript. It is so seductive, and yet so wrong! Very much like the dark side of the Force.

As I said earlier though, most of my viewmodel code is declarations of dependency properties for binding, with relatively small amounts of code in my verb methods. So I haven't honestly found too much temptation to do the wrong thing.

The key seems to be getting the mindset that everything centers around binding. Either directly to the rich data and metadata provided directly by CSLA objects, or to the additional properties defined by the viewmodel.

Lennon replied on Monday, March 15, 2010

Hi Rocky, our views are instantiating the view models through the WPF binding engine - i.e. each viewmodel is a resource on the associated view.  This requires a parameterless constructor.  Currently the Model property of each ViewModel is being set in its constructor using an IoC container.  However, we now want to use the BeginRefresh() method on ViewModelBase to call the appropriate factory method on the business object.  The question is, how can we determine if we are creating a new instance of a business object, or loading an existing business object in the constructor of the ViewModel?  How should this be handled?

Lennon replied on Monday, March 29, 2010

Hi Rocky,

How do you determine in your ViewModel constructors whether you are creating a new instance of the model or refreshing an existing instance?  Do you not require logic to determine the factory method on the business object to call?

RockfordLhotka replied on Monday, March 29, 2010

This depends on how you are creating your viewmodel objects.

I am usually navigating (in concept at least) from one viewmodel to another. So the current viewmodel creates an instance of the new viewmodel and then asks my UI framework to create a view, bind the view to this new viewmodel and show the view.

Which means my viewmodels have one or more constructors that are used by other viewmodels as needed.

What this means is that in most cases the default ctor calls the "new" factory, while some other ctor that takes a parameter calls the "get" factory.

Russ replied on Thursday, May 20, 2010

RockfordLhotka
Regarding abandoning CslaDataProvider, I think I've been talked into keeping it around until version 4.1 to give people time to transition off that model.

I'm just converting a 3.8 app to 4.0 and I'm getting the "The tag 'CslaDataProvider' does not exist in XML namespace 'clr-namespace:Csla.Wpf;assembly=Csla'." errors.  CslaDataProvider appears to have been moved from the Csla assembly. The quote above suggests CslaDataProvider may have been kept in Csla 4.0. If so, where does it live now?

RockfordLhotka replied on Thursday, May 20, 2010

There's now a Csla.Xaml.dll with a Csla.Xaml namespace - this is where the Csla.Wpf components now live.

Andreas replied on Sunday, February 28, 2010

Have a look at the ProjetTrackerPrism project at the CslaContrib. I implemented a class called DelegateCommandReplacement which I use instead of PRISM’s DelegateCommand. This will probably solve your problem. The only restriction is that it is currently working with WPF only.
The trick is to register the command implementation with CommandManager.RequerySuggested event. The event is raised by wpf when the CommandManager detects conditions that might change the ability of a command to execute. 

Andreas

Copyright (c) Marimer LLC