tags:

views:

1643

answers:

4


Update

In the wiki spirit of StackOverflow, here's an update:

I spiked Joe White's IValueConverter suggestion below. It works like a charm.

I've written a "quickstart" example of this that automates the mapping of ViewModels->Views using some cheap string replacement. If no View is found to represent the ViewModel, it defaults to an "Under Construction" page. I'm dubbing this approach "WPF MVVM White" since it was Joe White's idea. Here are a couple screenshots.

The first image is a case of "[SomeControlName]ViewModel" has a corresponding "[SomeControlName]View", based on pure naming convention. The second is a case where the ModelView doesn't have any views to represent it. No more ResourceDictionaries with long ViewModel to View mappings. It's pure naming convention now.

Wpf Mvvm White

I'm hosting a download of the project here: http://rootsilver.com/files/Mvvm.White.Quickstart.zip

I'll follow up with a longer blog post walk through.


Original Post

I read Josh Smith's fantastic MSDN article on WPF MVVM over the weekend. It's destined to be a cult classic.

It took me a while to wrap my head around the magic of asking WPF to render the ViewModel.

It's like saying "Here's a class, WPF. Go figure out which UI to use to present it."

For those who missed this magic, WPF can do this by looking up the View for ModelView in the ResourceDictionary mapping and pulling out the corresponding View. (Scroll down to Figure 10 Supplying a View ).

The first thing that jumps out at me immediately is that there's already a strong naming convention of:

classNameView  ("View" suffix)
classNameViewModel ("ViewModel" suffix)

My question is:

Since the ResourceDictionary can be manipulated programatically, I"m wondering if anyone has managed to Regex.Replace the whole thing away, so the lookup is automatic, and any new View/ViewModels get resolved by virtue of their naming convention?

[Edit] What I'm imagining is a hook/interception into ResourceDictionary.

... Also considering a method at startup that uses interop to pull out *View$ and *ViewModel$ class names to build the DataTemplate dictionary in code:

//build list
foreach ....
    String.Format("<DataTemplate DataType=\"{x:Type vm:{0} }\"><v:{1} /></DataTemplate>", ...)
A: 

If you go down this road, you might consider inserting actual DataTemplate objects into the ResourceDictionary, instead of trying to generate XAML.

Remember, it's just a dictionary, and these are just objects.

La Cabra
+7  A: 

Rather than writing code to explicitly add things to the ResourceDictionary, how about just generating the right view on demand? You can do this with a ValueConverter.

Your resources would look like this:

<Views:ConventionOverConfigurationConverter x:Key="MyConverter"/>
<DataTemplate DataType="{x:Type ViewModels:ViewModelBase}">
    <ContentControl Content="{Binding Converter={StaticResource MyConverter}}"/>
</DataTemplate>

You still need a DataTemplate resource, but as long as your ViewModels all have a common base class, you'll only need one DataTemplate to take care of all of them.

Then define the value converter class:

public class ConventionOverConfigurationConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        // value is the ViewModel. Based on its GetType(), build a string
        // with the namespace-qualified name of the view class, then:
        return Activator.CreateInstance(Type.GetType(viewName));
    }
    public object ConvertBack(object value, Type targetType,
        object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

All you'd need to do is write the logic inside Convert, which will depend on things like whether your Views and ViewModels are in the same namespace or not.

Joe White
that, sir, is exactly what i want to do! =)
Jeffrey Knight
Thanks Joe -- I updated this question based on your feedback.
Jeffrey Knight
Excellent! That's cut my App.xaml from a few hundred lines to a few tens :)
Groky
this is absolutely amazing.. I wish I had thought of this or seen this post 9 months ago. Would have saved me A LOT of time.
Jose
A: 

I decided to do pretty much hthe same thing so I load my DataTemplates directly into the ResourceDictionary using

    private void RegisterResources()
    {
        ResourceDictionary dictionary = new ResourceDictionary();
        dictionary.Source = new Uri("pack://application:,,,/StartupModule;Component/UIResources.xaml");
        Application.Current.Resources.MergedDictionaries.Add(dictionary);
    }

where the UIResources file is a ResourceDictionary xamls file containing all of our DataTemplates

Mark Green
A: 

This looks great for user controls and such. I have an application with several pages. Each page has a viewmodel. Is it possible to still use this? How would I navigate from one page to another?

WPFEnthusiast