views:

779

answers:

6

We built an large application based on Composite Application Library and MVVM using Infragistics controls.

In order to save time and make the application more straight-forward, we scrapped the MVVM requirement. We now have no Presenters or ViewModels and our Views have become simple UserControls which are created like this:

BaseEditor.cs:

using System.Windows.Controls;

namespace App
{
    public class BaseEditor : UserControl
    {
        public string Title { get; set; }
        public BaseEditor()
        {
            Title = "This was defined in the Base Editor.";
            Loaded += new System.Windows.RoutedEventHandler(BaseEditor_Loaded);
        }

        void BaseEditor_Loaded(object sender, System.Windows.RoutedEventArgs e)
        {
            StackPanel sp = new StackPanel();
            TextBlock tb = new TextBlock();
            tb.Text = Title;
            sp.Children.Add(tb);
            this.Content = sp;
        }
    }
}

CustomerEditor.cs:

namespace App
{
    public class CustomerEditor : BaseEditor
    {
        public CustomerEditor()
        {
            Title = "This was overwritten by the CustomerEditor.";
        }
    }
}

Window1.cs.xaml:

<Window x:Class="App.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:App"
    Title="Window1" Height="300" Width="300">
    <Grid>
        <local:CustomerEditor/>
    </Grid>
</Window>

Apart from the testability issue and the fact that this "feels dirty" doing WPF like this, I have only experienced positive effects from this decision, e.g.:

  • we can inherit our non-XAML UserControls from each other
  • we use as much code-behind as we want which expedites development
  • attaching the infragistic controls directly to our model class coming from the web service cleared up dozens of little binding problems we were having with binding Infragistics to ObservableCollections
  • even in straight WPF, the lack of ObservableCollections make problems like not being able to create a simple Menu go away
  • we are replacing the EventAggregator one-by-one with direct events using UserControls and code behind, which cleared up all kinds of problems with events

Has anyone else doing MVVM in WPF had similar experiences? Did you meet with any real problems in the long run?

+3  A: 

I tried this and ended up going back to MVVM. You end up with the same event-driven spagetti-coded mess you always ended up with in Windows Forms. If I never have to do another myLabel.Text = this.MyLabelText I will be happy.

Don't get me wrong - MVVM is harder to stick with and you really have to know WPF to pull it off.

You lose a lot by not using it, though, including a lot of the ability to use Expression Blend to style your controls and DataTemplates.

Anderson Imes
+2  A: 

Hey, whatever works for you. It's all too easy to get religious about this stuff. My apps slide into spaghetti code unless I pay pretty strict attention to Separation of Concerns, but that doesn't mean MVVM is the only way to go. If you've got an app that works, and one that you can change without a bunch of cascading side effects, then I'd say go with it.

I would respectfully disagree (no downvote) with Anderson Imes on one point: I don't find MVVM difficult to stick with; I find it very easy. To me, it is the simplest and most natural approach to designing WPF apps. I use it within the framework of Composite WPF (Prism), which provides a very robust framework for partitioning complex apps.

I have written a CodeProject article on implementing MVVM in a real-world app. Hopefully, people just getting into MVVM will find it helpful.

David Veeneman
If you are coming from WinForms, MVVM is not natural and has a steeper learning curve is all I'm saying... you have to learn a lot about WPF Binding, DataContexts, AttachedProperties, etc to really get it to pay off for you.
Anderson Imes
MVVM makes a lot of sense on the whole, perhaps we were just trying to do too much with it, i.e. create dynamic forms based on XML from the services. With UserControls bound to the model we have so much more control.
Edward Tanguay
Anderson--Yes, I would agree that coming from WinForms, MVVM can have a learning curve. MVVM is much easier to learn if you have WinForms experience with the Model-View-Controller pattern, which has many similarities to MVVM.
David Veeneman
Edward--Yes, it does sound like you may have been trying to do more with MVVM than the pattern can handle. Instead of creating dynamic forms, the current best practice appears to be to use Prism to load modules into a shell window as you need them, much as you seem to be doing with the user controls. Prism would definitely be worth a look, because it provides great infrastructure for loosely-coupled communications between modules.
David Veeneman
+1  A: 

A view model is good because it makes databinding easier. Databinding does not cover all that you need to do, so some code attached to the XAML is convenient.

In my experience a mix of view model and attaching to events seems to get the job done until a more pure approach can be worked out if required.

EDIT:

Attaching to events does not necessarily break the MVVM model if you use the event handler to forward the event to handler logic in your viewmodel or some other responsible object.

There are advantages to pure databinding in that you can more easily make different XAML skins which use the same viewmodel. One example is to have a debug skin which exposes some of the inner workings to help in development and a working skin which is the end product. The different XAML views can bind to the same viewmodel.

Doug Ferguson
+14  A: 

we can inherit our non-XAML UserControls from each other

I don't understand. What about MVVM precludes inheritance?

we use as much code-behind as we want which expedites development

Code-behind is fine as long as it's code that is concerned with the view. ie. not business logic that you want to test. Separation of concerns and all.

You can still do MVVM whilst doing everything in code - even your view. MVVM is not about zero code behind. It's about separating concerns and the benefits you derive from that. If you have no need to design your views in Blend, then by all means you can manifest much or all of the view as code. Heck, even if you do need to do work in Blend, there's a certain amount of your view that could still be manifested as code. You just need to evaluate the trade-offs and make conscious and informed decisions.

attaching the infragistic controls directly to our model class coming from the web service cleared up dozens of little binding problems we were having with binding Infragistics to ObservableCollections

The Infragistics controls are extremely poor. There, I said it. If it's an option, don't use them. If it is not an option (and I've been in this position too), you can normally work around many issues with attached behaviors and other techniques. It's a hassle, yes, but don't blame MVVM - blame Infragistics for producing a control set that is so at odds with the WPF platform.

even in straight WPF, the lack of ObservableCollections make problems like not being able to create a simple Menu go away

I don't understand this point at all. ObservableCollections are part of WPF, not MVVM. And having read your question (again - I replied to it not long after you submitted it) I'd say this is just your misunderstanding of how WPF works - nothing to do with MVVM at all.

we are replacing the EventAggregator one-by-one with direct events using UserControls and code behind, which cleared up all kinds of problems with events

Right tool for the right job. If you're able to use direct events, then you can do so whether you're using MVVM or not. MVVM does not in any way require the use of the event aggregator pattern, so again your point is unclear. The event aggregator pattern can be used to ensure that different components can collaborate at runtime without having any compile-time dependencies. By using standard CLR events, you're creating strong dependencies between your components. Should you ever want to use them in isolation, you're gonna have one heck of a time.

In summary, this doesn't much of a case against MVVM, but more a lack of understanding. I think you're swimming upstream and I'd advise you to take a closer look at MVVM. It's not a silver bullet or one-size-fits-all pattern, but it can sure help create a fantastic basis for your WPF/SL applications when used correctly.

HTH, Kent

Kent Boogaart
+1 on the Event Aggregator points. I've seen a lot of misunderstanding about its use... a lot of people think that when using MVVM + Prism you *must* use the Event Aggregator to raise events, when this is simply not true.
Anderson Imes
I gotta say man... I've reread this like 10 times. Well done breaking down his comments. I didn't read the OP's post as closely as you did... you really hit every point. Very nice.
Anderson Imes
Thanks for this long response, very useful. I will take a closer look at MVVM once we get past our deadlines which plain old winform-like user-control programming is helping us attain. What about MVVM precludes inheritance? I understand a View as a UserControl with XAML and code-behind. If you have a CustomerEditorView and an EmployeeEditorView and you realize that these have similar features which they should inherite from a BaseEditorView, you can't inherit XAML as you can a pure code UserControl as in the code above. That was one major win for us when we switched for example.
Edward Tanguay
Another point I didn't mention is: with MVVM, your ViewModels have to have all the properties of the Model and it seemed to be unnecessary code replication in the many cases which we weren't using the INotifyPropertyChanged functionality. This went away when we connected the UserControl directly to the model, and the validation e.g. that we were using INotifyPropertyChanged for, we now do in simple code behind where we need it.
Edward Tanguay
ObservableCollections are part of WPF: yeah, I know that, but instead of spending days trying to get a simple MenuItems to bind on an observablecollection correctly (http://stackoverflow.com/questions/1067903/how-can-i-bind-an-observablecollection-of-viewmodels-to-a-menuitem), I now spend minutes just building it in code behind, which cannot be tested by a mock view on my viewmodel, but which accomplishes the simple task quickly.
Edward Tanguay
+4  A: 

I started doing WPF applications in a FFA (free-for-all) design pattern like this and I won't go back it, even for a small projects. Though it feels like you are more productive going right to the source, bare-metal UI, I came to the conclusion it's more a perception of productivity because you get instant gratification.

Consider: TextBlock.Text = "HelloWorld". No ViewModel to construct, no gluing the V and VM or binding setups. Hit F5 and we see "HelloWorld" in all it's glory. My problem with this is multifaceted. Here is a couple of my biggest issues:

  • Separation of concerns. Without it, code navigation, bug fixing, extensibility and general maintenance is severely hindered. Adding a feature to an application would be more liken to a choose-your-own-adventure book or an exercise in quantum physics than it is actually getting something done. If you have a predictable way to build your app, you have a predictable way to work on it.

    Flexibility of the UI. When using the FFA pattern, I found my ability to design UI in my applications was near impossible. Too many times did I have a control I couldn't design in Blend. It would just give a red border with an exception. Some code-behind I had used something else that wasn't usable in design mode causing an issue. Moving to MVVM magically fixed all my Blend issues. If I get a red border in Blend now, I KNOW it's a problem with my presentation code. Not anything else.

So using FFA may get your V1 out the door quick, but the PHBs will be wondering why v1.5 is going to take four times longer than v1. We've all been there :)

I think if you want to do something like this, I would work with lookless controls, where you define UI "PARTS", making it very Blendable. You get reference to the UI controls via the OnApplyTemplate. These controls are totally stylable and inheritable. It is your View where you would use these controls and pull data from binding, passing it to your lookless controls. The View, IMO, should always be glue for the VM to bind to these kinds of controls.

For the Infragistics controls you are having problems with, assuming you are using Prism, you should make a custom region adaptor for it. This lets you code EXACTLY how controls will be added to the Infragistics. No binding involved. View injection will just work like you are used to once you get that built in.

I've seen some people have problems like these in MVVM, but I believe it's just taking MVVM too literally. Not everything gets evented by a messenger. My ~40 view (and growing) application has around 5 composite events. I inherit controls, I use view injection on things that aren't even panels or content controls. Sometimes I have codebehind handle presentation related code/events...And...really, I advocate MVVM and I don't give a @$&% about testing :)

Jeremiah Morrill
I would like to see a real-world demo application done with MVVM (and not one that does some simple thing like StockTrader) but something that connects to a database with full crud ability, one that uses infragistics or telerik or some real-world third-party components, and that have some kind of scalability such as controls being injected over project boundaries. When all these real-world aspects come into your application, one is bound to back off from MVVM, it would be a good to see WHERE one backs off and to see what the trade-offs are, limited UI testing, etc.
Edward Tanguay
A: 

I don't agree with this, I have worked on a large scale buisness application using WPF, MVVM, WCF and Telerik controls. In the beginning, using MVVM was a bit tough but once we settled with our design and the View model framework it became very easy. Reusability was very easily achievable and development time was also reduced.

Moreover it was really very easy to change the controls altogether; in some places we had used basic WPF controls which we later replaced with telerik controls and vice versa(as in some places we didn't required heavy telerik controls like GridView). I can say that if needed we could have easily replaced all telerik controls with some other 3'rd party controls or native WPF controls easily any time.

But yes, we had to implement some workarounds while using telerik controls and write some code in codebehind to solve some issues(bugs in telerik); all that code was purely presentation logic.

akjoshi