How to NOT use the CslaDataProvider in Silverlight?

How to NOT use the CslaDataProvider in Silverlight?

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


dpk posted on Wednesday, March 03, 2010

I'm quite familiar with CSLA.NET for WinForms and WPF but I'm struggling to make the mental leap to CSLA for Silverlight in a couple of areas.

I tend not to use the CslaDataProvider. I like to instantiate business objects myself and control their lifetime, usually in a VIewModel. What I'm struggling with is how to write the initialization code in the VM that creates and / or loads business objects. Given the asynchronous nature of Silverlight and the CSLA DataPortal, how would one write code that instantiates an object but performs some other work. If the call to the Create_____ factory method is async, how do I wait for that call to return before continuing? I've looked at some examples that talk about blocking the non-UI thread but this seems like a lot of code just to instantiate an object. Is that really how it has to work? My apologies if this seems a bit vague but after reading far too many blog posts and articles I'm really not sure what is the right way.

Regards,
Dave

RockfordLhotka replied on Wednesday, March 03, 2010

This is the reason for the ViewModelBase and ViewModel classes - to help manage these details.

The data provider model's strength was in defining a communication model that worked in sync and async scenarios - including reporting errors and providing the resulting data when it was available.

The ViewModel base class does this too. You are still required to create (or at least trigger the creation) of the business object, but the base class takes care of updating the Model property when the object actually arrives on the client, or the Error property in the case of an async error.

Of course you can implement other properties and verb methods on the viewmodel class - but the basic required functionality for a typical business object is already there with these base classes.

For example, here's a viewmodel that supports a simple edit screen (create an object, let the user edit the properties, save the object):

(this is CSLA 4 - but the 3.8 code would be extremely comparable)

using System;
using Csla.Xaml;
using Bxf;

namespace Collective
{
  public class PostEditViewModel : ViewModel<Library.PostEdit>
  {
    public PostEditViewModel()
    {
      Presenter.Instance.ShowStatus(new Status { IsBusy = true, Text = "Creating post" });
      BeginRefresh("NewPostEdit");
    }

    protected override void OnRefreshed()
    {
      base.OnRefreshed();
      Presenter.Instance.ShowStatus(new Status());
    }

    protected override void OnError(Exception error)
    {
      base.OnError(error);
      Presenter.Instance.ShowError(error.ToString(), "Search data error");
      Presenter.Instance.ShowStatus(new Status());
    }

    public override void Save(object sender, ExecuteEventArgs e)
    {
      Presenter.Instance.ShowStatus(new Status { IsBusy = true, Text = "Saving..." });
      base.Save(sender, e);
    }

    protected override void OnSaved()
    {
      Presenter.Instance.ShowStatus(new Status { IsOk = true, Text = "Post saved" });
      base.OnSaved();
    }

    public void Close()
    {
      Presenter.Instance.ShowView(null, null, null, "Content");
    }
  }
}

The Bxf namespace and Presenter construct are from a small (Basic Xaml Framework: Bxf) UI framework I'm playing with. But that's secondary - the important thing for your question is to understand how the viewmodel class works.

The constructor(s) call BeginRefresh(), passing in the name (and parameters) of the static factory method - which is async of course. That starts the process of creating or fetching the business object.

If the create/fetch works, the Model property is set, which automatically updates the UI via binding (the UI binds to the Model property). In my case I'm overriding OnRefreshed() to do some status bar update work.

If the create/fetch/save fails, the Error property is set, which might automatically update some UI element. In my case the OnError() override is triggering the UI framework to display the error and update the status bar.

The base class already has a Save() method that does the right thing. I'm overriding Save() just to do status bar updates, and the same with overriding OnSaved().

The Close() method is a verb - invoked through the TriggerAction (like InvokeMethod or Execute) component when the user makes the appropriate UI gesture to close this form. In my UI this is a button click, but it could be any appropriate UI event.

dpk replied on Thursday, March 04, 2010

Hi Rocky,

Thanks for the detailed reply. I think I see what you're doing here and I'll have to play around with it to see if this works in my situation. However, I do have some lingering conerns that this approach may not address:

1. Use of the term "ViewModel" in this case is confusing to me. I've been working with MVVM for a while and my view (no pun intended) is that a ViewModel represents a "model of the view". In my work a view is never always tied one-to-one with a business object. I usually create base classes called "ViewModelBase" that provide basic INotifyPropertyChanged functionality and other standard mechanisms used by all VMs, but I do not presume - as it appears you do - that a VM will always have a business object.

2. If I had a view that supported multiple business objects (say, in a collection) that are editable, would it mean that I would have a "view model" that has properties for each of the business objects that would be of type Csla.Silverlgith.ViewModel?

3. Can you point me to a sample project that shows how to "trigger" the creation of a business object?

Thanks again.
Dave

dpk replied on Thursday, March 04, 2010

Dan,

Your first sentence sums up my perspective. Regarding acronyms, one of the original blog posts I read around this MVVM pattern called it DM-V-VM for "Data Model" - View -ViewModel (http://blogs.msdn.com/dancre/archive/2006/07/23/676272.aspx). I think this is actually clearer.

Dan Billingsley
some of your confusion stems from prior experiences with VM that are different than what it does with a rich Model like one based on CSLA.

Not taken as condescending at all. Every use of MVVM so far for me has been with CSLA-based objects.

RockfordLhotka replied on Thursday, March 04, 2010

Please don't take this the wrong way - but I have a hard time caring whether my "MVVM" is pure or not.

I rather suspect it isn't. But that's OK, because in numerous conversations with MVVM purists it has become clear to me that they aren't looking for productivity, maintainabilty or cost-effective development. They are looking for testability.

Now testability is a fine goal - but only if it serves to improve the maintainability and quality of software - with the ultimate goal of reducing cost of development and long-term mainenance.

A lot of the MVVM stuff I've seen increases the amount of code in the app substantially. Some viewmodel classes have 2-3 times as much code as the model. To which I say WTF???

And it is an explicit non-goal for MVVM to eliminate code-behind. That's OK with me - but it is my explicit goal to eliminate code-behind. Because in the Xaml world code-behind is evil - specifically because it creates inescapable coupling between the Xaml and whatever code is behind the Xaml - thus preventing (human) designers from reshaping the Xaml in a decoupled manner.

On top of all this is the (erroneous) assumption that all models are anemic. Now if you have an anemic model, putting tons of code into the viewmodel is probably necessary - though ugly and ultimately (imo) counterproductive.

But if you are using well-designed CSLA business domain objects, you not only have a rich model, but one that is designed to support the use case. So why you would put much code into a viewmodel is entirely beyond my comprehension. It is just busywork.

The thing is, I don't think we disagree - other than on silly semantic issues.

If your model is well-designed it will fit naturally under your UI. But it won't have the verbs/commands/methods necessary for the UI to actually work. The UI might require a ShowDetail command, which clearly wouldn't be in the model - which is where the viewmodel comes into play. The viewmodel implements the verbs/commands required by the UI process flow. And it very possibly exposes extra properties (usually metaproperties) that provide extra information required by the UI, but not really meaningful to the model.

So the viewmodel is all about the view. But if your model is well designed, the model is shaped well for use by the view, so it is a natural to wrap the model with a thin viewmodel that just extends what's already there.

In a bigger app this isn't always true. Most apps I've built over the last couple decades have had tons and tons of forms that were basic CRUD - one object, or a parent-child model or other pretty basic scenarios. These are the ones I'm talking about. Probably 80% of all forms in most apps fit this scenario and are well-served by having a rich model with a thin viewmodel.

Then every app has a small number (sometimes just one) of forms that are complex. The order entry form, ticketing form, invoicing form, whatever. The top-level viewmodel for such a form might not correspond to a single object, but sub-regions of the form almost certainly do. Such forms end up with a mix of viewmodel types - some that subclass ViewModelBase and some that subclass DependencyObject.

And, at least the way I usually build my apps, there's always the main shell window. Which typically has no business object at all, because it is pure UI concerns - managing the toolbar, nav bar, status bar, work area(s) and dialogs. It has a viewmodel that subclasses DependencyObject and exposes numerous properties and perhaps a few verbs/commands necessary to build a completely data bound Xaml shell window.

But even that's not enough - not in any real sense. You also need a message router and renderer. No viewmodel code can ever, ever, ever interact with a concrete Xaml type or instance - including your view types. As soon as you do that you lose the ability to test. So anything like creating/showing a view, or showing status or error information, or adding/removing items from a toolbar must be done through some abstract messaging router and renderer. That allows you to swap out the router and renderer with test versions at test time - versions that don't actual route or render anything - thus allowing the viewmodel code to be tested in an automated server environment where the UI elements don't exist.

TSF replied on Thursday, March 04, 2010

Rocky - do any of the downloadable code examples that you've posted demonstrate CSLA for Silverlight utilizing MVVM design considerations?  If so, could you point me to the location of those examples?  Thank you.

RockfordLhotka replied on Thursday, March 04, 2010

Not in a complete way. The MVVMexperiment projects (SL and WPF) illustrate the basic use of the various MVVM components provided in 3.8.

dpk replied on Thursday, March 04, 2010

Rocky, I agree with nearly everything in your post because that is how I do MVVM. I just can't agree with using the term ViewModel to describe what your base classes do. 

My ViewModelBase would implement at least INotifyPropertyChanged, but only to be used to inform data binding of changes to the metaproperties in the VM. The CSLA-based business object would be exposed as a property of the VM. I would also have (in WPF) some ICommand properties. What I would need to do when I use your classes is have a property whose type is not, for example, "Customer" but rather ViewModel<Customer>. So my VM has a property whose type is "ViewModel<T>" but it's not the same as the ViewModel class that contains it (eg, CustomerEditViewModel). They have very different purposes.

Well, that's my case. I know my opinion will not change anything, and it really doesn't have to and that's not my goal. I started this thread trying to understand how to use CSLA-based business objects in SL with the whole async-thingy. You have pointed me to the solution. I'm eager to get started using it.

Thanks as always for your wisdom and taking more than a few moments to assist me.

Regards,
Dave

RockfordLhotka replied on Thursday, March 04, 2010

Ahh, but ViewModelBase is a DependencyObject, so it implements INotifyPropertyChanged and is fully bindable in Xaml.

Additionally, ViewModelBase is designed specifically so you can implement some ICommand properties if you want to use commanding. I find commanding far to limiting (and of course it isn't in SL), so I use alternatives.

This is specifically why ViewModelBase only implements protected methods - so you can implement your own public methods based on your UI framework of choice. Usually those public methods just call the protected methods that already do the work.

The ViewModel<T> class is one example of creating a more specialized subclass of ViewModelBase. It implements several public methods that work with InvokeMethod/Execute/TriggerAction.

But of course if you are using some other UI framework I'd expect you to create your own equivalent to ViewModel<T> based on ViewModelBase with public methods that work with your particular UI framework's invocation model (be that ICommand or something else).

jasonlaw replied on Thursday, March 04, 2010

Hi Rocky,

I am very interested to know how the Bxf works.

I understand that it will be part of your MVVM video, but is there any chance that this simple UI framework will be open to everyone just like CSLA ?

Thank you.

Jason

RockfordLhotka replied on Thursday, March 04, 2010

jasonlaw

I understand that it will be part of your MVVM video, but is there any chance that this simple UI framework will be open to everyone just like CSLA ?

I don't know yet. I don't have the bandwidth to give care and feeding to another framework - CSLA is already so big I can't do it by myself anymore.

Nor do I really plan to create anything nearly as comprehensive as Prism or many of the other Xaml MVVM frameworks out there.

But I am learning a lot of interesting things with Bxf (which is my primary motivation in building it), and I absolutely plan to share that in some manner.

dpk replied on Friday, March 05, 2010

Rocky,

One thing I'm still hung up on is unit testing a CSLA-based business object for Silverlight. Can you point me to some example code in the downloads? Specifically I'm trying to understand how to deal with creating a new BO using the async factory methods. Perhaps this is not strictly a CSLA question. I'm playing around with ManualResetEvent but I think I'm missing something.

If I wanted to test inserting an object, I have to create one first. Here's my test code:

        private static ManualResetEvent waitHandle;

 

        public static Role CreateObject()

        {

            waitHandle = new ManualResetEvent(false);

            waitHandle.Reset();

 

            Role obj = null;

            Role.NewRole((o, e) =>

            {

                obj = e.Object;

                obj.Name = "Name";

                obj.Description = "Description";

                waitHandle.Set();

            });

            bool result = waitHandle.WaitOne(5000);

            if (result)

                return obj;

            else

                throw new Exception("CreateObject timed out.");

        }

 

        [TestMethod]

        public void Insert()

        {

            UnitTestContext context = GetContext();

            var obj = CreateObject();

            waitHandle = new ManualResetEvent(false);

            obj.BeginSave((o, e) =>

            {

                var savedObject = (Role)e.NewObject;

                context.Assert.IsNull(e.Error);

                context.Assert.IsNotNull(savedObject);

                context.Assert.IsFalse(savedObject.IsNew);

                context.Assert.IsFalse(savedObject.IsDirty);

                context.Assert.IsFalse(savedObject.IsDeleted);

                context.Assert.Success();

            });

        }

The problem is that the waitHandle times out.


Now, my test code may not be correct yet and I haven't introduced any mocking and such yet. I'm just trying a proof-of-concept of sorts to see if I can get a single object to work from UI to DB and back and all of the layers in between.

Thanks,
Dave

dpk replied on Friday, March 05, 2010

I'm going to post this as a new question.

RockfordLhotka replied on Thursday, March 04, 2010

You can read my blog posts (http://www.lhotka.net/weblog) to see my transition from MVVM skeptic to advocate.

That transition came when I realized that most applications of MVVM assume an anemic model, while CSLA provides a rich model. So to not expose the business object to the UI via the viewmodel with CSLA is an insane amount of work and, frankly, is counter-productive. This assumes, of course, that you want all the benefits of actually using CSLA (data binding support, business/validation rules, authorization rules).

Were you to try to "wrap" CSLA objects behind viewmodel objects, as people often do with anemic models, and still get the value of CSLA, your viewmodel will have more code than your business object! You'd have to re-implement all the data binding, validation and authorization interfaces with code that echoes everything bi-directionally between the UI and business objects. Totally counter-productive.

While I do agree with you that the viewmodel is part of the UI, and is tied to the view - I think it is critical to realize that a good behavioral object model is also shaped by the view, or at least the use case and user experience - which is usually another way of saying "the view".

In other words, if your CSLA objects look like your database, then you are doing your object modeling wrong. But if your objects look (much) like your UI then you are probably closer to correct in your object modeling.

The result, then, of good OOD is a Model that closely matches the requirements of the user experience and thus the UI. Of course there are still UI-specific concerns - verb methods and properties that exist only to support the UI, which is why the viewmodel is so useful.

In a practical sense, I have numerous viewmodel objects per form - at least for more complex forms. Simple CRUD forms like the one corresponding to the viewmodel code I posted yesterday are quite common, and the ViewModel<T> class makes creating those forms trivial. But more complex forms often involve numerous viewmodel types - essentially one for each "region" of the form.

So I'll typically have one form-level viewmodel that may or may not subclass ViewModel<T> (depending on whether there's a root object bound at the top level of the form). If not, then I subclass DependencyObject so I get all the bi-directional binding support offered by Xaml. Then I'll have "child viewmodel" objects that provide appropriate services to sub-regions of the form.

For example, in an order entry form there's the order header info at the top of the form, and a list of line items in the middle, and an area at the bottom for editing the selected line item.

In that case the top-level viewmodel would be a ViewModel<OrderEdit>, the line item list control would be bound to a ViewModel<LineItemList>, each row in the list would be bound to a ViewModel<LineItem>, and the edit area at the bottom would be a different ViewModel<LineItem>. So I might have four viewmodel classes, each providing verbs and properties required to support the Xaml for those various elements of the view.

The ViewModel<OrderEdit> would be the "root" viewmodel - I literally create a tree or graph structure of my viewmodel types so they automatically and clearly interlink - which makes it easy to code the viewmodel classes, but more importantly makes it easy for the Xaml to access all the various instances directly through binding expressions.

Another wrinkle with the use of Xaml, is that generally speaking it is the Xaml that creates the viewmodel. At least if you are like me and have a rule that there is never any code-behind a form. If you have zero code-behind, and you want decent binding support, the view will contain at least the top-level viewmodel as a Resource, which means when the view is created, it will create the viewmodel instance. Which is why in my earlier code example you see that it is the viewmodel constructor that calls BeginRefresh() to go create/fetch the business object.

Now in VS10 things are a little more indirect - probably for the better. In VS10 (assuming you use the Xaml designer) the Resource will always be a CollectionViewSource object - so that's what gets created when the view is created. This is nice, because it means your broader UI framework (whether that be MVC, MVP or whatever) can do this:

  1. Create the view (which creates the CollectionViewSource, with a Source of null)
  2. Create the root viewmodel for the form
  3. Set the CollectionViewSource.Source property to the viewmodel
  4. Display the new view

This is the scenario my prototype Bxf framework targets - so it has complete and natural integration with the VS10 designer, while requiring zero code-behind, keeping the viewmodel simple and keeping all the business/validation/authorization logic in the business layer.

Sadly I'm not quite in a position to release the code I'm working on - as at least right now the Bxf stuff will be part of the MVVM video I'm planning to release in April.

dpk replied on Thursday, March 04, 2010

Rocky,

First off, I have been implementing business objects frameworks with CSLA since the VB6 days and have been a huge advocate for its use since then. So, I understand the benefits completely. My issue is probably both semantics and definition around "ViewModel". As I stated before, a VM to me represents a "model of the view". Like you, I nest VMs within VMs, essentially constructing a complete object graph that represents the UI. I think only in terms of VMs and only consider the view last. From TDD perspective, this allows me to concentrate on testing UI interaction while only having to consider the actual UI from an abstract sense. I don't think of Buttons but rather Commands (or whatever other method you want to use), or ObservableCollection<T> instead of ListBox. Some parts of the UI utilize CSLA-based business objects, but not all. In my VM I might have other properties that trigger things to happen in the UI, such as boolean properties that can be used with a ValueConverter to turn things on or off.

Now, when it comes to exposing CSLA-based business objects, I totally agree with you. I expose them directly to the view and allow the view to bind directly to the properties of the BO. It makes no sense to wrap a CSLA-based object and with a bunch of other properties that simply delegate. Again, I never presume, though, that a VM even has a CSLA business object. So, your use of "ViewModel<T>" as a wrapper around a business object to simplify object lifetime is in my opinion different from what VM really means in MVVM. Just my opinion, although it comes from reading many articles around the subject from which my perspective was formed. It would make more sense in my view that your class be called "ModelConnector<T>" or "ModelAdapter<T>". Again, I think we have a difference in perspective on the definition of a VM and consequently the use of the word "ViewModel" exposes this difference. One or the other has to change (staring match ensues....).

Next, I am also of the school that you never (almost never) have code-behind in your views. What's interesting, however, is how a view and viewmodel get connected. In the WPF world I use a technique where I create a DataTemplate in a resource file that points to the VM type and tells it which view to use, This happens automatically via data binding and resource management in WPF by setting the DataType attribute of the DataTemplate to the type of the VM:

 <DataTemplate DataType="{x:Type localVM:MainViewModel}">
     <localViews:MainView></localViews:MainView>
</DataTemplate>

In this way the view is automatically hooked up to the VM and the view's DataContext is automatically set to the VM. This doesn't seem to work in SL. So it's only now that I'm starting to see the various techniques around connecting views and VMs. I'm interested however in your statement that the "... generally speaking it is the Xaml that creates the viewmodel". If the VM is instantiated as a resource in the view, does this imply that you must have a parameterless constructor on the VM? I ask because I'm a fan of dependency injection, especially when it comes to using Prism for UI composition. I generally instantiate VMs from parent VMs so that I can pass in whatever parameters I need. For example, I might need to pass in the business object that is used in the VM as the data model. This usually happens when I'm processing a collection of child objects and will be creating a VM for each child to display in the view. (Or I pass in the collection as IList<T>). I'm starting to read about "view model locators" as another option. I would love to hear what other folks are doing as well.

One final observation. You're examples above include "ViewModel<OrderEdit>" which doesn't sound like a business object to me (I would have expected "Order"). Are you suggesting by this example that you are passing in some other class that is more in line with my view of a VM?

Regards,
Dave

 

Copyright (c) Marimer LLC