Share ViewModels

Topics: Prism v4 - WPF 4
Apr 15, 2013 at 9:34 AM
Hello,

How best way to share Modules ViewModels property for property values save setting to xml format.

Thanks so much.
Apr 15, 2013 at 5:27 PM
Hi,

It would be helpful is you could explain in more detail what you are trying to achieve so we can provide guidance to you.

Regards,

Federico Martinez
http://blogs.southworks.net/fmartinez
Apr 16, 2013 at 6:39 AM
Edited Apr 16, 2013 at 6:41 AM
Hello, Thanks for reply,

For example, we have two modules and each module a viewmodel we now how to share viewmodels if clicked save button all property save to xml format.

Modules1
namespace Modules.VM1.ViewModels
{
    [Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class VM1ViewModel : Infrastructure.ViewModels.NavigationAwareDataViewModel
    {
        [ImportingConstructor]
        public VM1ViewModel()
        {

        }

        private bool _isCheckBox;
        public bool IsCheckBox
        {
            get { return _isCheckBox; }
            set
            {
                _isCheckBox= value;
                this.RaisePropertyChanged(() => IsCheckBox);
            }
        }
}
Modules2
namespace Modules.VM2.ViewModels
{
    [Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class VM2ViewModel : Infrastructure.ViewModels.NavigationAwareDataViewModel
    {
        [ImportingConstructor]
        public VM2ViewModel()
        {

        }

        private bool _isRadioButton;
        public bool IsRadioButton
        {
            get { return _isRadioButton; }
            set
            {
                _isRadioButton= value;
                this.RaisePropertyChanged(() => IsRadioButton);
            }
        }
}
Apr 16, 2013 at 6:52 PM
Hi,

Based on my understanding, you are trying to save the data of each view model into a XML file. If this is your scenario, I think that a possible solution could be to use a shared service, which will be in charge of managing the process of saving this data. You should inject the service into each view model so that when you want to save the data, the view model will pass the information you want to save to the service and this one will then manage the saving. This way, the process of saving data to a XML file is decoupled from the view model.

A possible way to implement your shared service could be to use a queue to save the information of each of your view models in order so you can access and write the XML file one view model at a time. Therefore, you will avoid multiple simultaneous writings on the XML file that could cause to save wrong information.

Please let us know if we have misunderstood your scenario,

Federico Martinez
http://blogs.southworks.net/fmartinez
Apr 18, 2013 at 1:43 PM
Hello, Thanks for reply,

I'm implemented interface in class for share interface Module2 not load, Please see my code how to solved this problem.
namespace Modules.VM1.ViewModels
{
    [Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class VM1ViewModel : Infrastructure.ViewModels.NavigationAwareDataViewModel, IVM1ViewModel 
    {
        [ImportingConstructor]
        public VM1ViewModel()
        {

        }

        private bool _isCheckBox;
        public bool IsCheckBox
        {
            get { return _isCheckBox; }
            set
            {
                _isCheckBox= value;
                this.RaisePropertyChanged(() => IsCheckBox);
            }
        }

public interface IVM1ViewModel 
{
bool IsCheckBox { get; set; }
}

}
namespace Modules.VM2.ViewModels
{
    [Export]
    [PartCreationPolicy(CreationPolicy.Shared)]
    public class VM2ViewModel : Infrastructure.ViewModels.NavigationAwareDataViewModel, IVM2ViewModel 
    {
        [ImportingConstructor]
        public VM2ViewModel()
        {

        }

        [Import]
        public IVM1ViewModel VM1ViewModel{ get; set; }

        private bool _isRadioButton;
        public bool IsRadioButton
        {
            get { return _isRadioButton; }
            set
            {
                _isRadioButton= value;
                this.RaisePropertyChanged(() => IsRadioButton);
            }
        }

public interface IVM2ViewModel 
{

}
}
Developer
Apr 18, 2013 at 4:07 PM
Hi,

After checking your code I believe the problem might be related to how the classes are being exported in MEF.
Please try exporting the VM1ViewModel by changing the Export attribute like this:
[Export(typeof(IVM1ViewModel))]
[PartCreationPolicy(CreationPolicy.Shared)]
public class VM1ViewModel : Infrastructure.ViewModels.NavigationAwareDataViewModel, IVM1ViewModel
{
   ...
}
Regards,

Damian Cherubini
http://blogs.southworks.net/dcherubini
Apr 19, 2013 at 7:33 AM
Hello Cherubini, Thanks for reply,

I've got to try this method but had failed to solve my problem, I've got to upload the source if possible to see where is the problem.
Thanks.

http://bayfiles.com/file/OMGj/t4lQv5/Navigation.zip
Developer
Apr 19, 2013 at 8:10 PM
Hi,

First of all, I wasn't able to run your sample as out of the box, as the AtomicModuleLoader you were using was throwing exceptions. Instead I switched to the default ModuleLoader to test the sample. About this subject, I am not sure what you are trying to do with this custom loader, as it seems to try to download .xap files from a web server and your sample is a desktop application.

Regarding you problem with composition, I found that the Page1View could no be composed correctly by MEF. The reason behind this is an import in the view defined as this:
[Import]
public Page1ViewModel ViewModel { ... }
However, the Page1ViewModel type is being exported in the container throw the IPage1ViewModel interface. So in order to import it, you need to change the property to use the interface:
[Import]
public IPage1ViewModel ViewModel { ... }
After changing this the Page1View was composed correctly, along with the Page1ViewModel and the Page3ViewModel.

Also, take into account that as you are importing a type from a different module, it is advised to mark that module as a dependency in the module catalog:
<modularity:ModuleInfo Ref="file:///Navigation.Modules.Page1.dll" InitializationMode="OnDemand" ModuleName="Page1Module" ModuleType="" >
    <modularity:ModuleInfo.DependsOn>
        <sys:String>Page3Module</sys:String>
    </modularity:ModuleInfo.DependsOn>
</modularity:ModuleInfo>
I hope this helps,

Damian Cherubini
http://blogs.southworks.net/dcherubini
Apr 21, 2013 at 1:02 PM
Edited Apr 21, 2013 at 1:03 PM
Hello Cherubini,
Thank a lot, My problem was solved.
Apr 22, 2013 at 9:59 AM
Edited Apr 23, 2013 at 12:54 PM
+1
Apr 25, 2013 at 7:24 PM
Edited Apr 25, 2013 at 7:24 PM
Hello Cherubini,

If possible upload project switched to the default ModuleLoader?

Thanks.
Developer
Apr 26, 2013 at 5:25 PM
Hi,

You can find a version of your sample modified to use the default ModuleManager to load the modules in the following link:
I also added a ModuleTracker service to check if a module has been loaded or not.

I hope you find it useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini
Apr 27, 2013 at 8:22 AM
Hello Cherubini,
Thank a lot very useful for me.
Apr 27, 2013 at 11:39 AM
Hello Cherubini,

I'm change CreateModuleCatalog from CreateFromXaml to ConfigurationModuleCatalog this exception error, How to solved this problem, Thanks so much.

The composition produced a single composition error. The root cause is provided below. Review the CompositionException.Errors property for more detailed information.

1) Module Page1Module was not found in the catalog.

Resulting in: An exception occurred while calling the 'OnImportsSatisfied' method on type 'Navigation.Shell'.

Resulting in: Cannot activate part 'Navigation.Shell'.
Element: Navigation.Shell --> Navigation.Shell --> AssemblyCatalog (Assembly="Navigation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")

Resulting in: Cannot get export 'Navigation.Shell (ContractName="Navigation.Shell")' from part 'Navigation.Shell'.
Element: Navigation.Shell (ContractName="Navigation.Shell") --> Navigation.Shell --> AssemblyCatalog (Assembly="Navigation, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null")
        protected override IModuleCatalog CreateModuleCatalog()
        {
            return new ConfigurationModuleCatalog();
        }
<?xml version="1.0"?>
<configuration>

    <configSections>
        <section name="modules" type="Microsoft.Practices.Prism.Modularity.ModulesConfigurationSection, Microsoft.Practices.Prism"/>
    </configSections>

    <modules>
        <module assemblyFile="Navigation.Modules.Page1.dll" moduleType="Navigation.Modules.Page1.Page1Module, Navigation.Modules.Page1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" startupLoaded="true" moduleName="Page1Module">
        </module>
        <module assemblyFile="Navigation.Modules.Page2.dll" moduleType="Navigation.Modules.Page2.Page2Module, Navigation.Modules.Page2, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="Page2Module">
        </module>
        <module assemblyFile="Navigation.Modules.Page3.dll" moduleType="Navigation.Modules.Page3.Page3Module, Navigation.Modules.Page3, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" moduleName="Page3Module">
        </module>
    </modules>

    <startup>
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
    </startup>
</configuration>
Developer
Apr 29, 2013 at 7:59 PM
Hi,

Based on my understanding the problem is that the ConfigurationModuleCatalog and the module catalog obtained through CreateFromXaml are populated at different times: the one obtained from CreateFromXaml is populated at the moment of its creation (hence, before creating the Shell,) while the ConfigurationModuleCatalog is not populated until its Load method is invoked (hence, after the Shell is created.)

When you try to load the modules in the Shell, the ConfigurationModuleCatalog has not loaded the configuration yet and hence, it doesn't contain information about any module, throwing an exception.

A quick workaround to change this is to force the ConfigurationModuleCatalog to be populated when it's created, by doing something like this:
protected override IModuleCatalog CreateModuleCatalog()
{
    var moduleCatalog = new ConfigurationModuleCatalog();
    moduleCatalog.Load();
    return moduleCatalog;
}
Regards,

Damian Cherubini
http://blogs.southworks.net/dcherubini
Apr 29, 2013 at 8:21 PM
Thanks a lot, solved my problem.
May 9, 2013 at 12:02 PM
Edited May 9, 2013 at 12:02 PM
Hello Cherubini,

I have a issue with MEF in PRISM, After Import property in Page1ViewModel View module not load, please see project.

Thanks so much.

http://www.solidfiles.com/d/6b6ed98266
Developer
May 9, 2013 at 7:07 PM
Hi again,

The problem was that the RepositoryBase class was not being registered in MEF. Please remember that to export a type in MEF you need to:
  • Add the Export attribute to the type you want to export,
  • And register the assembly containing the type so that MEF inspects it for any classes that need to be exported.
The problem was in the second point. As the Navigation.Repository assembly was not added as a AssemblyCatalog or initialized as a module the RepositoryBase class was not being exported. You can solve this by adding a reference to the Navigation.Repository project in the Navigation main project and including the following line in the ConfigureAggregateCatalog method of the bootstrapper:
this.AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Repository.RepositoryBase).Assembly));
As a side note, this registration is not required when the project is loaded as a module by Prism, as it automatically registers the assembly to be inspected by MEF.

I hope this helps,

Damian Cherubini
http://blogs.southworks.net/dcherubini
May 10, 2013 at 7:45 AM
Thanks a lot, solved my problem.