MVVM and Modularity example using MEF

Topics: Prism v4 - Silverlight 4
Dec 6, 2010 at 1:30 AM
Edited Dec 6, 2010 at 1:22 PM

I am looking for a simple example that demonstrates mvvm and modularity concepts using MEF. Looking at examples provided in Prism 4.0, the MVVM examples don't use modularity and the modularity examples do not use MVVM. The Stock Trader RI uses both, but is too complex for MEF newbies. Is there anything in between?

I started out with a simple module that has one view and one view model, but I am not sure if I have used MEF in the best way possible. For example, is there a better way to create the view instead of using ServiceLocator in the module's Initialize( ) method? Here's are some code snippets from my application.

---------- HomeModule ----------
[ModuleExport(typeof(HomeModule))]
public class HomeModule : IModule
{
    IRegionManager _regionManager;

    [ImportingConstructor]
    public HomeModule(IRegionManager regionManager)
    {
        _regionManager = regionManager;
    }

    public void Initialize()
    {
        // Create the view
        IHomeView homeView = ServiceLocator.Current.GetInstance<IHomeView>();

        // Add it to the region
        IRegion region = _regionManager.Regions["MainRegion"];
        region.Add(homeView, "HomeView");
        region.Activate(homeView);
    }
}

---------- IHomeView (so that MEF can export HomeView) ----------
public interface IHomeView
{
}

---------- HomeView.xaml ----------
<UserControl ...>
    <StackPanel x:Name="LayoutRoot" Margin="10">
        <StackPanel Orientation="Horizontal" VerticalAlignment="Top">
            <TextBlock Text="Name" VerticalAlignment="Center" />
            <TextBox Width="100" VerticalAlignment="Center" Margin="10 0 0 0"
                     Text="{Binding Path=Name, Mode=TwoWay}" />
            <Button Content="Submit" VerticalAlignment="Center" Margin="10 0 0 0"
                    Command="{Binding SubmitCommand}"/>
        </StackPanel>
        <TextBlock Text="{Binding Message}" Margin="0 10 0 0" Foreground="Red" />
    </StackPanel>
</UserControl>

---------- HomeView.xaml.cs ----------
[Export(typeof(IHomeView))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public partial class HomeView : UserControl, IHomeView
{
    public HomeView()
    {
        InitializeComponent();
    }

    [Import]
    public IHomeViewModel ViewModel
    {
        set { this.DataContext = value; }
    }
}

---------- IHomeViewModel (so that MEF can export HomeViewModel) ----------
public interface IHomeViewModel
{
}

---------- HomeViewModel.cs ----------
[Export(typeof(IHomeViewModel))]
[PartCreationPolicy(CreationPolicy.NonShared)]
public class HomeViewModel : NotificationObject, IHomeViewModel
{
    public HomeViewModel()
    {
        this.SubmitCommand = new DelegateCommand<object>(this.OnSubmit);
    }

    private void OnSubmit(object obj)
    {
        Message = "Hello " + Name;
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (value != _name)
            {
                _name = value;
                this.RaisePropertyChanged("Name");
            }
        }
    }

    private string _message;
    public string Message
    {
        get { return _message; }
        set
        {
            if (value != _message)
            {
                _message = value;
                this.RaisePropertyChanged("Message");
            }
        }
    }

    public ICommand SubmitCommand { get; private set; }
}
Developer
Dec 6, 2010 at 5:37 PM
Edited Dec 7, 2010 at 5:00 PM

Hi,

You might find the following blog post from Karl Shifflett, as well as the Prism Training Kit useful to learn more about MEF in conjunction with MVVM and other topics of interest. You could also find the MEF Codeplex project useful to your purpose.

As for the approach you have taken for adding your view into a region, it isn't incorrect, but you could also use any of the other ways of Composing the UI, such as View Discovery. Obtaining a reference to the view and explicitly adding it to the region prgramatically (which is called View Injection) is only needed on scenarios where you can benefit from that complexity (that is to say, when you need explicit programmatic control of when views are added into regions). You can read more about this in this chapter from the Prism documentation.

I hope you find this helpful.

Guido Leandro Maliandi
http://blogs.southworks.net/gmaliandi

Dec 6, 2010 at 7:13 PM

they way I have done it and its annotated in the code snippet in HomeModule.cs. 

[Export(typeof(IHomeView))]
public class HomeView : UserControl, IHomeView
{
     //etc...
}

 

---------- HomeModule ----------
[ModuleExport(typeof(HomeModule))]
public class HomeModule : IModule
{
IRegionManager _regionManager;

[ImportingConstructor]
public HomeModule(IRegionManager regionManager)
{
_regionManager = regionManager;
}

public void Initialize()
{
// Create the view
//IHomeView homeView = ServiceLocator.Current.GetInstance<IHomeView>();

[Import(typeof(IHomeView))]
private IHomeView homeView {get;set;}


// Add it to the region
IRegion region = _regionManager.Regions["MainRegion"];
region.Add(homeView, "HomeView");
region.Activate(homeView);
}
}


I have this working in my current project now and it works just fine. The one difference from what I have is I use import/export in this fashion.
[Import("HomeView", typeof(IHomeView))] and the corresponding view has the Export equivalent. A concrete implementation of the import/export

Dec 11, 2010 at 1:29 PM

Guido and mvermef, thanks for pointing me in the right direction.

Dec 24, 2010 at 6:41 PM

HI Naresh,

 

I am also looking for the same thing. since i am new to it can you please send me your sample working code so that i can also check how thngs are working. thnx

Dec 27, 2010 at 6:01 AM

Hi Guys,

Hope this sample helps.

Dec 27, 2010 at 5:57 PM

Hi gan_s,

 

Thanks for the example but its throwing runtime exception

An unhandeled exception 

Microsfot.practices.prism. modularitay.ModuleTypeLoadingException Failed to load type for module moduleA and Module B

 

Dec 28, 2010 at 4:28 AM

I'll have a look tonight. It was running fine on my machine though !!

Dec 28, 2010 at 9:54 AM

at my side i can only see ModuleA and ModuleB button and underneath i see the text "Authencating" and after almost 2 second above mentioned exception comes up automatically.

 

Dec 28, 2010 at 9:56 AM

Can you see two sl projects ModuleA and ModuleB? Make sure they are loaded. And also ModuleA.xap and ModuleB.xap should be there in the ClientBin. If not just clean the solution and rebuild.

Dec 28, 2010 at 12:09 PM

Everything is there but in Iexplorer i am getting this url C:/Downloads/MefPrism/MefPrism/MefPrism/Bin/Debug/MefPrismTestPage.html#/moduleA

Might be UAC issue? any idea? furthermore, i am running visual studio in administrator mode 

 

Dec 28, 2010 at 12:17 PM

That is fine. That is how the sl navigation framework builds uris. Is the app working now?

Dec 28, 2010 at 12:28 PM

no still its giving me same exception. :-(

Dec 28, 2010 at 12:34 PM

Do you have IIS installed? If yes go to the Web project properties -> Web tab -> and create a virtual dierctory http://localhost/mef

Then set start url to http://localhost/mef/#/moduleA and then run your app. I'm checking the app locally in the meanwhile.

Dec 28, 2010 at 12:39 PM

Just checked. The app is working just fine. You'll need to figure out whats happening at your end. Here is a screenshot of the running app.

Dec 28, 2010 at 12:50 PM

same exception as before :-(

Dec 28, 2010 at 12:57 PM

Whats the full exception with stacktrace?

Dec 28, 2010 at 1:11 PM

you can find the complete exception here...

 

http://i1216.photobucket.com/albums/dd377/sirfmemon/exception.jpg

 

Dec 28, 2010 at 1:43 PM

No idea what the issue could be. You are all by yourself on this one :)

Dec 28, 2010 at 4:37 PM

It worked on my desktop but not working on laptop though its was also not working on desktop as well i fixed by enabling directory browsing from iis manager. working fine at desktop but not on laptop dont know why..

 

anyways, thanks

 

 

Dec 28, 2010 at 4:57 PM

is the web application set as the start up project, if one of the modules is setup as the start up project it could lead to this behavior.

Dec 29, 2010 at 6:09 AM

Glad I could help !

Dec 29, 2010 at 7:18 PM

Yes it was already set to startup project. but no luck. as i menteion its working on my desktop

Dec 30, 2010 at 6:05 AM

Could it be because of the clientaccesspolicy.xml missing in the Web project?