Reusing ViewModel for two Views?

Oct 2, 2012 at 1:11 PM

I know that the plain idea is to have a single ViewModel for every View, but I've an app where I have two Views presenting exactly the same set of data. So, is there a way how I can reuse a ViewModel for two Views?

Coordinator
Oct 3, 2012 at 9:33 AM

You should be able to use a view-model for multiple views by simply adding multiple ViewModelExport attributes. For example,

[ViewModelExport("PageA")]
[ViewModelExport("PageB")]
public class MyViewModel
{
    ...
}

Note however this will create a new instance of the view-model for each view (i.e. a single object definition but multiple instances). If you want to share actual data you could write a service class that is marked as [Shared] in MEF with a property to hold the shared data (if there are multiple data-sets you could have a MyDataService.GetMyData(string dataId) method instead). This can then be imported into the view-model and you will get a singleton instance. As a simple example,

[Export(typeof(MyDataService))]
[Shared]
public class MyDataService
{
    public MyData { get {...} }
    ...
}


[ViewModelExport("PageA")]
[ViewModelExport("PageB")]
public class MyViewModel
{
    [Import]
    public MyDataService { get; set; }
    ...
} 
Oct 3, 2012 at 11:55 AM

Well, I tried this, but I get a compile error: Duplicate 'ViewModelExport' Attribute...

Coordinator
Oct 3, 2012 at 12:21 PM

I've just checked and you are correct - this is a bug. I'll make sure it doesn't cause any problems and fix it for the next release of Okra.

For the meantime you can make this fix yourself by downloading the latest release from the CodePlex downloads section. In the 'Okra.MEF' project locate the 'ViewModelExportAttribute' and set AllowMultiple to true on the AttributeUsage attribute (it is currently set to false).

[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = false)]

Hopefully this should then work,

    Andy

Feb 27, 2013 at 10:39 PM
Hey Andy,
Was this update made to the Okra yet? Trying to do the same thing in a new project (used Nuget to install most current version) and I'm getting the same error.

Also, you say that:
Note however this will create a new instance of the view-model for each view (i.e. a single object definition but multiple instances).
So if I have 2 views that want to use the same VM that isn't possible?

Something like..
[ViewModelExport("PageA")]
[ViewModelExport("PageB")]
[Shared]
public class MyViewModel
{
    ...
} 
...wouldn't work?
Coordinator
Feb 28, 2013 at 12:15 PM
Hiya,

I thought I'd pushed the changes into the last Nuget drop of Okra (v0.9.5) so I will have to look into that for you. Maybe there is something else I have missed. Regarding the possibility of adding a [Shared] attribute to the view-model, I'm not sure how this would affect things so I'm using an ExportFactory to construct the view models but it sounds like it should work.

I'll check on this and let you know.

Andy
Coordinator
Feb 28, 2013 at 7:51 PM
Hello again,

I've just tested this and I can compile and run an example with a view-model with multiple attributes - could you please check that NuGet has delivered the latest version of Okra (version 0.9.5.0 - you can check this by right-clicking on the reference in the Visual Studio solution explorer and selecting "Properties"). I have also put the source code for my test app here - note that this is a very quick test app, not an example of great design or good practices!

Regarding the use of the [Shared] attribute : this was something I hadn't considered but wasn't sure how it would interact with the ExportFactory. I have tested this as well and you are right, if you add the [Shared] attribute then all pages will use the same view-model instance. Great!

Let me know if you are still having problems and I will investigate further,
Andy
Mar 1, 2013 at 2:59 PM
Hey Andy,
I was running 0.9.4.0. I just checked Nuget, and I see that 0.9.5.0 was released as of today, so I downloaded it and now I can build! I'll get around to actually testing the shared use of the ViewModel later, but I'll assume you're results are correct and it should just work. Exciting!