views:

826

answers:

5

Here's my scenario: 1) Shell with 1 TabControl and 1 region called MenuRegion 2) MenuRegion contains Buttons for each of the available modules (applications).

I want to achieve the following using Prism (Composite Application Library for WPF): When one of the buttons is clicked, I need to add a new TabItem to the TabControl, and load and individual instance of the corresponding module (application) inside this TabItem. One module may appear several times in the TabControl.

Please help.

A: 

We do something similar, though we have the tab items already created (with no content) and show/hide as appropriate. When the tab item is selected, then we load the tab content.

private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
 {
  if (e.OriginalSource != sender) return;

  TabControl tabControl = (TabControl)sender;
  TabItem tabItem = (TabItem)tabControl.SelectedItem;

  if (!tabItem.HasContent)
   AddTabContent(tabItem); // This will cause a refresh once the content is loaded.
  else
   Refresh(tabItem);
 }



private void AddTabContent(TabItem tabItem)
 {
  IOptimusPage page = tabItem.Tag as IOptimusPage;

  //This allows lazy loading of controls
  if (page != null)
  {
   if (!tabItem.HasContent)
   {
    CustomerEngagementUserControl control = page.GetControl(DataContext as CustomerEngagementUIObject, Services);

    tabItem.Content = control;
   }
  }

 }

The tab item content is specified in the tab item tag, using pages which are responsible for creating the content.

<TabItem
Header="Personal Background"
Style="{StaticResource FirstBreadcrumbTabItem}"
x:Name="PersonalBackgroundTab">
 <TabItem.Tag>
     <Pages:FfnaPersonalBackgroundPage />
 </TabItem.Tag>
</TabItem>

The page creates the control.

class FfnaPersonalBackgroundPage : IOptimusPage
{
 #region IOptimusPage Members

 public CustomerEngagementUserControl GetControl(CustomerEngagementUIObject dataContext, CustomerEngagementServices services)
 {
  CustomerEngagementUserControl control = new FfnaPersonalBackgroundControl();
  control.DataContext = dataContext;
  control.Services = services;
  return control;
 }

 #endregion
}

You could use a similar technique to create your tab items on the fly.

Donnelle
A: 

Hi Donnelle. I really appreciate your answer. But I don't believe you're using Prism (http://www.codeplex.com/CompositeWPF) are you? My question was more related to Prism, and I've edited it to be more clear now.

In Prism you dynamically load modules' views into regions. I am not sure how to do that in my scenario because the regions are to be set dynamically. How would I name them?

Thanks!

Gustavo Cavalcanti
A: 

I know it's quite late a response but I am doing something similar, although haven't achieved the full solution yet.

This code happens on the click event of a button which I am handling in the presenter. The module is defined in the config file.

ModuleInfo moduleInfoObject = this.moduleEnumerator.GetModule("ModuleA"); 

Assembly assembly = this.LoadAssembly(moduleInfoObject);

Type type = assembly.GetType(moduleInfoObject.ModuleType);
IModule aModule = this.CreateModule(type);                                    
aModule.Initialize();  


// - - - -Helper Methods - - - -
// - - - LoadAssembly - - -       
private Assembly LoadAssembly(ModuleInfo moduleInfo)
    {            
        string assemblyFile = moduleInfo.AssemblyFile;
        assemblyFile = this.GetModulePath(assemblyFile);

        FileInfo file = new FileInfo(assemblyFile);
        Assembly assembly;

        try
        {
            assembly = Assembly.LoadFrom(file.FullName);
        } 
        catch (Exception ex)
        {
            throw new ModuleLoadException(null, assemblyFile, ex.Message, ex);
        } 

        return assembly;

    } // LoadAssembly(moduleInfo)


// - - - CreateModule - - -
private IModule CreateModule(Type type)
    {
        return (IModule)containerFacade.Resolve(type);            
    } // CreateModule(type)


// - - - GetModulePath - - -
private string GetModulePath(string assemblyFile)
    {
        if (String.IsNullOrEmpty(assemblyFile))
        {
            throw new ArgumentNullException("assemblyFile");
        } // if

        if (Path.IsPathRooted(assemblyFile) == false)
        {
            assemblyFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, assemblyFile);
        } // if

        return assemblyFile;
    } // GetModulePath(assemblyFile)
A: 

Hello Gustavo,

I am looking for exactly the same as you doing.

Did you find a solution, if so can you post the code snippet.

Appriciate your help.

Anwar

I haven't yet Anwar. I will post here once I have an answer.Thanks
Gustavo Cavalcanti
+1  A: 

Hello Gustavo,

I 'm new to this PRISM world (1 week experience :)) ) and had the same requirement! First of all you have to get the Regionextensions from here. The solution to my (may be your) problem is as follows: -have 2 regions (menu and tabcontrol - for mdi like behaviour)

-tabitem header has to be prepared with a button for closing (which is bound to a command for closing this tabitem-actually hiding this tabitem)

-send event from menu item to the module which should load the view (i've instantiated the modules on demand). In the module's initialize method subscribe to the event sent by the menu item. In the event handling method you simply re-show the tabitem

If this is to abstract to you i can sent you a skeleton application i 've developed to play around.

Cheers

Savvas

savvas sopiadis