View adding to Region Exception

Topics: Prism v4 - Silverlight 4
Jan 27, 2011 at 3:29 PM

Dear All,

I created a Menu module that hold the menu definition of my application, exactly as the prevuiosly created AVTModule.

The difference is that this menumodule is registered to the MianNavigationRegion.

This is my MenuModule class:

	[ModuleExport(typeof(MenusModule))]
	public class MenusModule : IModule
	{
		[Import]
		public IRegionManager RegionManager;
		
		public void Initialize()
		{
			RegionManager.RegisterViewWithRegion(RegionNames.MainNavigationRegion, 
			typeof(Views.AppMainMenuView));
		}
	}
And I add the xaml definition in the cataloge as follows:
<Modularity:ModuleInfo Ref="GL.Modules.Menu.xap" InitializationMode="WhenAvailable" 
	ModuleName="MenusModule" 
 	ModuleType="GL.Modules.Menu.MenusModule, MenusModule, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/>
This module class is responsible to register the appmainmenuview in the MainNavigationRegion
Here is my AppMainMenuView:
	[Export("AppMainMenuView")]
	public partial class AppMainMenuView : UserControl
	{
		public AppMainMenuView()
		{
			InitializeComponent();
		}
		[Import]
		public AppMainMenuViewModel ViewModel
		{
			get { return this.DataContext as AppMainMenuViewModel; }
			set { this.DataContext = value; }
		}
	}
And also my AppMainMenuViewModel:
	[Export]
	public class AppMainMenuViewModel : NotificationObject
	{
	}
Nothing complicated right !!.
I succesfully can load the other module (AVTModule) into the mainRegion but not this one to the NavigationRegion !!!
What is the error here ...
Any help is appreciated
Regards
Jan 27, 2011 at 3:50 PM
Edited Jan 27, 2011 at 4:12 PM

Need to add this, if I add the menu from the shell it work just fine ...

The VS2010 halted, when I restarted it doesn't give the exception when call from MenuModel class, but not shown neither from the shell or the MenuModel class ..

What is the funny thing here ...

 Just in case this is my xaml definition of the MainNavigationRegion in the shell.

<Border x:Name="MenuBorder" Style="{StaticResource MenuBorderStyle}"> 
	<StackPanel> 
		<StackPanel x:Name="MenuStackPanel" Style="{StaticResource LinksStackPanelStyle}" > 
			<TextBlock Text="Menu Should Appear here"/> 
			<ItemsControl x:Name="NavigationItemsControl" prism:RegionManager.RegionName="MainNavigationRegion" /> 
		</StackPanel> 
	</StackPanel> 
</Border>
Developer
Jan 27, 2011 at 4:56 PM

Hi Waleed,

The problem you're experiencing might be because you're exporting your view with a contract name. You could try specifying an Export without a contract name for your view, for example:

	[Export] // no contract name here
public partial class AppMainMenuView : UserControl
{
public AppMainMenuView()
{
InitializeComponent();
}
[Import]
public AppMainMenuViewModel ViewModel
{
get { return this.DataContext as AppMainMenuViewModel; }
set { this.DataContext = value; }
}
}

I hope you find this helpful.

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

Jan 27, 2011 at 5:08 PM
Edited Jan 27, 2011 at 5:27 PM

Well, it works ... but this is strange !!

I mean if I have a view in the same application with the shell, the view will not be available unless I add "Contract Name" if I removed it, it will not show; of course no exception in both cases.

But I would like you explain if possible what is the difference here ...

Appreciate you reply indeed

Regards

Waleed

 

Edited:

Also I would like to add that the DelegateCommand on the shell-viewmodel is not working (call view from another xap), even If I specify the full URI as follows :

/GL.Modules.Menu;component/Views/AppMainMenuView

Another thing is:

If I try to load the view in the LoadModuleCompleted event from the shell, it works ....

I am lost overhere

Developer
Jan 27, 2011 at 5:31 PM

When you export a composable part in MEF, you need to define the contract that it will be exported with. If you don't indicate a string or type for the contract, the part will be exported with its type as the contract type. You can read more about it in the Mef Programming Guide.

From the description of the overload you're using of the RegisterViewWithRegion method, it is used to: "Associate a view with a region, by registering a type. When the region get's displayed this type will be resolved using the ServiceLocator into a concrete instance. The instance will be added to the Views collection of the region." Therefore, that overload will attempt to resolve the view you have defined, but if you have used a contract that is different from the type you're specifying in the RegisterViewWithRegion method, the ServiceLocator will be unable to retrieve that instance, and therefore it won't be added to the region.

One possibility to achieve your requirement without having to specify a default contract name would be to use another overload of the RegisterViewWithRegion, which would retrieve the instance of your view through the use of a custom delegate . From the description of this overload, it is used to: "Associate a view with a region, using a delegate to resolve a concreate instance of the view. When the region get's displayed, this delelgate will be called and the result will be added to the views collection of the region." For example:

RegionManager.RegisterViewWithRegion("MainRegion", () => ServiceLocator.Current.GetInstance<YourViewType>("YourViewContract"));

As for the DelegateCommand issue you're mentioning, it would be helpful if you could provide us with more details about what you've implemented in the command's logic.

I hope you find this helpful.

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

Developer
Jan 27, 2011 at 5:34 PM

I'm sorry, I didn't read the update you've made regarding your DelegateCommand. As for your concern, it isn't recommended to put the code for adding a view inside the Shell ViewModel. You should place the logic to add a view to a region inside the module that contains that view.

I hope you find this helpful.

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

Feb 2, 2011 at 10:50 AM

Sorry for my late reply, I guess you are aware of Egypt events.

I would like to add that if I put the [Export("viewName", typeof(view))] it will work in both cases.

Why it isn't recommended to put the event handlers in the viewodel ... whereelse.

Best regards

Waleed

Feb 3, 2011 at 1:52 PM

Hi Waleed,

The reason why is not recommended to place this kind of logic in the shell, is because your application will be losing the approaches Prism tries to solve. As documentation shows:

…The guidance is designed to help architects and developers achieve the following objectives:

· Create an application from modules that can be built, assembled, and, optionally, deployed by independent teams using WPF or Silverlight.

· Minimize cross-team dependencies and allow teams to specialize in different areas, such as user interface (UI) design, business logic implementation, and infrastructure code development.

· Use an architecture that promotes reusability across independent teams.

· Increase the quality of applications by abstracting common services that are available to all the teams.

· Incrementally integrate new capabilities.

Therefore, as you separate your applications in modules, like Guido recommends, you might benefit with features such as:

  • Reusability
  • Testability
  • Interact in a loosely coupled way

You might find useful the following link of Prism documentation:

Chapter 4: Modular Application Development

I hope you find this information useful.

Thanks,

Miguel Bronzovic
http://blogs.southworks.net/mbronzovic

 

Feb 4, 2011 at 1:58 PM

Hello,

I am seperating my application into modules already ...!!

you talked about the things that realy attrackted me to PRISM4, you didn't reply where to define & where to wire the events ...

Regards