MVVM support in the framework

May 5, 2009 at 4:03 AM
Edited May 5, 2009 at 4:05 AM
Hey guys

We've been doing a bunch of thinking around stuff we can do in the platform to further enable MVVM development.

I posted on the topic here.

http://codebetter.com/blogs/glenn.block/archive/2009/05/04/view-model-the-movie-cast-your-vote.aspx

Any feedback is welcome.

Thanks
Glenn
May 5, 2009 at 4:39 PM
Some of the pain points that I experience regarding WPF and MVVM are these:
  • Magic strings
  • INotifyPropertyChanged
  • Setting the initial DataContext
Here are some ways that the framework could help alleviate some of that pain.

First, don't databind to named properties. Instead, databind to an interface. Write one interface in C#/VB, import it into Blend, and implement it with the View Model. Better yet, let it be a composite interface to support factoring. And make it possible to modify the interface from within either Blend or Visual Studio. This will give us compile-time validation of data binding, and it will give the tools more information about data types.

Second, (shameless plug) use a dependency discovery algorithm like Update Controls rather than explicit change notification.

Third, come up with a way for me to declaratively construct the View Model from app.xaml and make it the DataContext of the view. Perhaps make it more IoC friendly? I want NO code behind.
May 5, 2009 at 6:03 PM
In other words...resuscitate Acropolis!
Coordinator
May 5, 2009 at 6:16 PM
Yeah... it would be quite interesting to see Acropolis Open Sourced for a while, to let folks like us go crazy in it, and then take the best concepts that result from there and rework them to fit in the framework.  There's certainly things in Acropolis I'd do differently, especially considering what we've learned and advances in WPF, but there's still a lot of stuff in there that we really should have equivalents to in the framework.

On Tue, May 5, 2009 at 2:03 PM, mbrownbh <notifications@codeplex.com> wrote:

From: mbrownbh

In other words...resuscitate Acropolis!

Read the full discussion online.

To add a post to this discussion, reply to this email (mvvmref@discussions.codeplex.com)

To start a new discussion for this project, email mvvmref@discussions.codeplex.com

You are receiving this email because you subscribed to this discussion on CodePlex. You can unsubscribe or change your settings on codePlex.com.

Please note: Images and attachments will be removed from emails. Any posts to this discussion will also be available online at codeplex.com




--
Quidquid latine dictum sit, altum sonatur.
- Whatever is said in Latin sounds profound.

War is peace. Freedom is slavery.  Bugs are features.
May 5, 2009 at 6:24 PM
Edited May 5, 2009 at 6:25 PM
I'll talk to David Hill about Acropolis source. :-)

How does that help specifically from an MVVM standpoint?

Glenn
May 5, 2009 at 7:06 PM
Glenn,
Acropolis addressed everything Michael Perry mentioned with the original CTP. Declarative ViewModels is a BIG win. App.xaml served as a container for wiring up services and components. I think with a bit of work, it could be a HUGE productivity boost. It would even enable a top down scenario where the designer says, I need this property exposed from the viewmodel. Instead of dropping into code, he could declare it. Just as we have attached behaviors for UI we could have attached VM behaviors like RetrieveFromDatabaseBehavior. Pretty soon, we'd be able to design UI and VM in Blend.

Also I wrote a post a while ago (back when Acropolis was hot) discussing how it could be easy to map use cases (or stories or scenarios or whatever you want to call it) onto acropolis VMs. Mapped onto "Oslo" it would be feasible to see how the entire application can turn into a diagram on Quadrant.

That's how it helps from an MVVM standpoint ;)
May 5, 2009 at 7:33 PM
I see, so you want to allow dynamically defining new properties in XAML. I'd be lying to say that worries me, as it introduces a lot of magic that will be difficult to validate. How would it work anyway? Meaning I have a model behind the scenes, and now I want to add a new property, are you saying the designer browses the OM and finds the thing they want and create a prop def on the fly that points to it?

Glenn


May 5, 2009 at 7:42 PM
Sounds about right to me ;)

Not dynamically defining new properties. Just declaring them. We already do this with dependency properties. I declare it using DependencyProperty.Register. From what I recall, Acropolis did just that (with the added benefit of using generics). It's been a while since I've done anything with it so I might have romantacized it...but there was a hell of a lot of potential there.
May 5, 2009 at 8:26 PM
I don't know anything about Acropolis. Looks like I have some catching up to do there.

What I'm asking for is type-safe data binding using a .NET interface. I want all of the properties declared in the interface, and I want DataContext to be an instance of that interface.

The designer in Blend should have to select from among the defined properties when binding a control. If the property he needs is not there, he should be able to add it to the interface. This means checking out the .cs or .vb file, adding the property declaration (in a designer-friendly way), and checking it back in. All within Blend. When the developer gets latest, his build should break until he adds that property to the View Model.

This may be crazy talk. I speak only for myself.
May 5, 2009 at 8:35 PM
Acropolis was a framework that was released as CTP a few years back. It had a designer for App.xaml and creating a view also generated a corresponding vm with its own XAML and codebehind.
May 5, 2009 at 9:04 PM
Ha ha ressuscitating Acropolis, Brad Abrams is going to have a blast :) The first time I met him was in Redmond for an "introduction to Acropolis" talk, shortly before it was, well, recycled into other technologies ;)

Iteration is the rule!
May 5, 2009 at 9:08 PM
Ha....acropolis pages still up on windowsclient.net  http://windowsclient.net/acropolis/default.aspx
May 6, 2009 at 9:40 AM
Edited May 14, 2009 at 5:36 PM

Here is an idea, how about using the WF in .NET 4 for ViewModels. Though, I’ve not played with it personally, from what I know it has a pretty extensive declarative model and I understand you can use it to declare xaml-based properties/classes. Also, we can perhaps expose ICommands as activities, and handle all the ins and outs in a declarative way too.  Plus, I suppose because it is xaml based, I am guessing it might also avail the use of behaviours. And with some twisting support for navigating views can be directly build in, as an earlier WF extension did. If someone has played with WF 4, maybe they can speak to such possibilities?

 

Rishi

May 14, 2009 at 1:14 PM

Hearing all this talk about creating/modifying VMs in Blend worries me a little... All the effort that was put in the powerful binding features so the developer is able to write and test a class in isolation from the view (which is the designer's domain) starts blurring the domains again with the designer having the power to add functionality/properties that are not covered in unit tests.

I'd really like having more tooling/infrastructure for creating the VMs, but making edition of the VMs designer friendly is a little too much. Designers should be able to work with VMs (or maybe mocked VMs) that developer provides. If the designer needs an extra property to store some transient presentation state value for wiring up a combobox to a scrollbar (to say something strange), let him use attached behaviors.

My 2 cents.

Julian

May 14, 2009 at 3:18 PM

I may have been unclear in my original post. I am not for creating View Models in Blend. I am not for dynamically generating View Models.

I am for a type-safe contract between designer and developer. I am for defining an interface for the View Model.

Blend can import a class from a project and present its properties to the designer for binding. It cannot import an interface. I'd like to see this fixed.

If you define a data template in Blend, it does not recognize that its DataContext is a member of the ItemsSource of the parent control. I'd like to see this fixed.

I would also like to see the contract become a two-way discussion between developer and designer. Just as the developer can check out an interface and add a property, so too should the designer. If the designer adds a property to the interface and the developer's View Model does not implement that property, the build should break.

As it is today, XAML data binding uses magic strings. Magic strings don't break builds. They don't even throw exceptions. Only through expensive manual testing can we see if the contract between developer and designer is broken.

May 14, 2009 at 4:55 PM

HI Michael, timely conversation. :-)

I've been pondering something similar (based on conversations with Shawn Wildermuth and Pete Brown) for the new VM work we are currently planning in the framework. My thinking was using an interface for VM, but not necessarily requiring the VM to implement it. An interface would provide a strongly typed representation of what members were expected on the VM. Even if the VM doesn't actually implement the interface, tooling can go against it and verify whether or not those members are present on the VM.

For example if I have a VM like this

public class OrderVM {

  public string Order {get;set;}

}

and an interface like this

public interface IOrderVMContract { 

  string Order {get;set;}

}

And some way of declaring it in the view

<OrderView x:DataContextContract="IOrderVMContract"/>

Then:

1. Tooling (Cider/Blend) can populate the members in their dialogs.

2. An MSBuild task can validate bindings against OrderVM, by comparing it's members to the contract, or any other VM for that matter, as only the shape of the VM matters rather than the interfaces it implements.

3. I could potentially have inline validation inside the tool in the future.

4. Tools like Cider / Blend "could" generate a proxy over the contract for a designer data experience.

5. A designer could add new properties in the IDE which whould modify the contract, thereby giving the developer clear information about what is needed on the VM.

Thoughts?

Glenn

Coordinator
May 14, 2009 at 5:59 PM

Why would you not want the VM to implement the interface?

Why do we need an interface for these features? Why not specify OrderVM instead of IOrderVMContract? Or at least allow either, so we don't have to crate an artificial interface if it's not needed.

This doesn't seem to really provide "pure" static checking, since the "contract" and the "datacontext" aren't statically enforced to be the same (I can specify IOderVMContract declaratively, and then programmatically set the DataContext to "new object()" which doesn't satisfy the contract, and the best the framework could do is provide an immediate exception rather than a more cryptic binding error).  It's a step up, yes, but we're still not to the point of doing static verification.  I personally don't think you need static verification.  Heck, even with the way things are today, I have never run into a binding error that wasn't trivial to find and correct.  Something like this would be nice, but it might be nicer just to have an automated way to flag binding errors in regular integration/UI testing.  Our testers are going to visit every page anyway, regardless of what other tooling does, so if the discovery of binding errors happened in an automated way during this testing, there's no time lost.

May 14, 2009 at 6:08 PM

It "could", but i am saying it would not have to. The reasoning is you might be using a model that you do not own the source for, but which is bound to.

As far as the integration testing, if we have MS-Build integration you would get the static checking. The build task would use the interface to validate against the datasource. It would allow you to pick up binding errors at compile time. It probably won't catch setting the DataContext = an object, though potentially it could.

 

May 14, 2009 at 6:11 PM

Adding on to this, having a contract which the designer owns would allow a graphic designer to add new properties they believe they need in the UI. They won't have the code for the VM so they can't add the property to it directly. But, they can add it to the interface. If our tools generated light proxies for data, they could actually give a design-time implementation with those properties. Then when the developer gets the updated contract, they can see they need to add those properties to the VM.

Glenn

May 14, 2009 at 6:12 PM

I am perhaps a stricter advocate of static type checking than some. So I would prefer that the framework enforce the type of DataContext. But I realize that the cat is out of the bag on this one. We can't go back and make System.Windows.FrameworkElement a generic without breaking every consumer of WPF.

As an advocate of static checking, I would prefer if the VM had to implement the interface. Rather than rely on an optional build task, this would bring the checking right into the IDE and enforce it. But again, that requires a sweeping framework change.

So I guess the only tooling changes I could ask for are:

  1. Allow me to select an interface in the Blend data binding wizard.
  2. Make Blend aware that if ItemsSource is bound to an IEnumerable<IOrderLineViewModel>, then the DataContext of the order line data template has to be an IOrderLineViewModel.
May 14, 2009 at 6:14 PM

Michael.

I am actually in the same boat. Maybe we could purse having a FrameworkElement<TDataContext> for those who want a more statically enforced experience?

Glenn

May 14, 2009 at 7:08 PM

Glenn,

I for one would love that.

Following the Dependency Inversion Principle, I would expand FrameworkElement<TDataContext> with an interface, rather than the concrete VM. Then I could inject DataContext via IoC.

Makes me smile just thinking about it.

-Michael

May 14, 2009 at 7:27 PM

Yes, absolutely! Actually with NOPIA which is coming in .NET 4.0 and possible SL 4.0, you'll be able to do more with that than you think ie. structural (duck) typing. Meaning you can have "partial" interfaces where one interface has a subset of the members in another though they share no common reference, yet they cast to be equivalent by the CLR.

OK, well I am not sure whether we'll have the bandwidth but I will throw it on the backlog. The problem with FrameworkElement<T> as Nikhil pointed out to me is that it is viral in terms of requiring an entire set of generic objects under the hood. ;-)

Glenn