0
votes

I am using Prism + MEF

I have fairly simple application. I have shell with a region "Region1". Have a module as separate project with MyUserControl.xaml, MyUserControlVM.cs and ModuleA.cs. This usercontrol has to be shown in Shell--> Region1. For that I have added this usercontrol into the region in the ModuleA.cs

Now MyUserControlVM is not injected into the UserControl Datacontext.

    [ModuleExport(typeof(ModuleA))]
    public class ModuleA : IModule
    {
        public void Initialize()
        {
            var regionManager = ServiceLocator.Current.GetInstance<IRegionManager>();

            regionManager.Regions["Region1"].Add(new MyUserControl());
        }
    }

MyuserControl.Xaml

<StackPanel>
    <Label Content="{Binding Message}" Height="38" HorizontalAlignment="Left" Name="label1" VerticalAlignment="Top" Width="193" Background="#FFD8CFCF" />
    <Label Content="ABC"></Label>
</StackPanel>

MyUserControl.Xaml.cs

public partial class MyUserControl : UserControl
    {
        public MyUserControl()
        {
            InitializeComponent();
        }

        [Import]
        public MyUserControlVM ViewModel
        {
          get { return this.DataContext as MyUserControlVM; }
          set { this.DataContext = value; }
       }        
   }

MyUserControlVM.cs

    [Export(typeof(MyUserControlVM))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class MyUserControlVM : INotifyPropertyChanged
    {
        private string _message;

        public string Message
        {
            get { return _message; }
            set
            {
                _message = value;
                NotifyPropertyChanged("Message");
            }
        }


        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string propertyName)
        {
            if(PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

Region defined in Shell.Xaml:

<Grid>
    <ContentControl Name="Region1" regions:RegionManager.RegionName="Region1" Margin="70">
            </ContentControl>
</Grid>

App.xaml.cs is like this

        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            var bootstrapper = new Bootstrapper();
            bootstrapper.Run();
        }

BootStrapper is like this

    public class Bootstrapper : MefBootstrapper
    {
        protected override DependencyObject CreateShell()
        {
            return Container.GetExportedValue<Shell>();
        }

        protected override void InitializeShell()
        {
            base.InitializeShell();
            App.Current.MainWindow = (Window)Shell;
            App.Current.MainWindow.Show();
        }

        protected override void ConfigureAggregateCatalog()
        {
            base.ConfigureAggregateCatalog();

            AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(Shell).Assembly));
            AggregateCatalog.Catalogs.Add(new AssemblyCatalog(typeof(ModuleLibrary.ModuleA).Assembly));

        }

    }

Please help me where I am doing wrong.

1

1 Answers

0
votes

The answer is very simple.

You create an instance of your view (MyUserControl) explicitly:

regionManager.Regions["Region1"].Add(new MyUserControl());

In this case, MEF does not participate in the object's life cycle.

Let Prism create the view instance for you, so the object can be handled by the IoC container (including the part composition and dependency injections):

regionManager.RegisterViewWithRegion("Region1", typeof(MyUserControl));

Additionally, I would suggest you to avoid the ServiceLocator anti-pattern:

ServiceLocator.Current.GetInstance<IRegionManager>();

Instead of this, use a dependency injection:

[ModuleExport(typeof(ModuleA))]
public class ModuleA : IModule
{
    private readonly IRegionManager regionManager;

    [ImportingConstructor]
    public ModuleA(IRegionManager regionManager)
    {
        this.regionManager = regionManager;
    }

    public void Initialize()
    {
        this.regionManager.RegisterViewWithRegion("Region1", typeof(MyUserControl));
    }
}