Thursday, September 24, 2009

Prism - Creating a Custom Region Adapter for Ribbon

After using the Office Ribbon control in my WPF application, I thought to include that in a CWPFG project. My first step was to create a custom region adapter (OfficeRibbonRegionAdapter) that inherits from the RegionAdapterBase<Ribbon> .

public class OfficeRibbonRegionAdapter : RegionAdapterBase<Ribbon>

{

public OfficeRibbonRegionAdapter(IRegionBehaviorFactory regionBehaviourFactory) : base(regionBehaviourFactory) { }

//Maintain the ribbon instance

private Ribbon ___Instance;

protected override void Adapt(IRegion region, Ribbon ribbon)

{

___Instance = ribbon;

ribbon.Tabs.Clear();

//Implementing the collectionChanged handler

region.ActiveViews.CollectionChanged +=

new System.Collections.Specialized.NotifyCollectionChangedEventHandler((x, y) =>

{

switch (y.Action)

{

case NotifyCollectionChangedAction.Add:

foreach (RibbonTab __RibbonTab in y.NewItems)

___Instance.Tabs.Add(__RibbonTab);

break;

case NotifyCollectionChangedAction.Remove:

foreach (RibbonTab __RibbonTab in y.NewItems)

___Instance.Tabs.Remove(__RibbonTab);

break;

}

});

region.ActiveViews.ToList().ForEach( x => ribbon.Tabs.Add(x as RibbonTab));

}

protected override IRegion CreateRegion()

{

//This region keeps all the views in it as active.

//Deactivation of views is not allowed.

//This is the region used for ItemsControl controls.

return new AllActiveRegion();

}

}

Once the adapter is ready you can register it with the RegionAdapterMappings

var __Mappings = base.ConfigureRegionAdapterMappings();

__Mappings.RegisterMapping(typeof(Microsoft.Windows.Controls.Ribbon.Ribbon), this.Container.Resolve<OfficeRibbonRegionAdapter>());

return __Mappings;

Now we can create RibbonTabs in individual modules

RibbonTab __FolderTab = new RibbonTab();

__FolderTab.Label = "Folder";

RibbonGroup __FolderGroup = new RibbonGroup();

__FolderGroup.GroupSizeDefinitions = FindResource("FolderGroup") as Collection<RibbonGroupSizeDefinition>;

RibbonButton __DocButton = CreateRibbonButton("DocCommand");

RibbonButton __MusicButton = CreateRibbonButton("MusicCommand");

RibbonButton __PictureButton = CreateRibbonButton("PictureCommand");

RibbonButton __VideosButton = CreateRibbonButton("VideosCommand");

__FolderGroup.Controls.Add(__DocButton);

__FolderGroup.Controls.Add(__MusicButton);

__FolderGroup.Controls.Add(__PictureButton);

__FolderGroup.Controls.Add(__VideosButton);

__FolderTab.Groups.Add(__FolderGroup);

return __FolderTab;

Once the ribbon tabs are ready you can add it to the Region using ViewDiscoveryUIComposition method or using the Add method like

___RegionManager.RegisterViewWithRegion("ShellRibbon", () => ___Container.Resolve<RibbonView>().FolderRibbonTab);

Or

___RegionManager.Regions["ShellRibbon"].Add(___RibbonView.OfficeRibbonTab);

Output




5 comments:

Anonymous said...

Very good article. I am currently working on a project using Prism and trying to use the office ribbin control. Can you share the sample source code for the region adapter?

Anonymous said...

Hi,

where to place this Adapter? in the CAL Composite.Presentation.Desktop.Regions folder??

Prajeesh Prathap said...

You can put this in a project which is accessible to your Views.
I have included that in the Infrastructure/ Regions folder

Anonymous said...

Hi Prajeesh, Can you post the code for the method 'CreateRibbonButton'. I am trying to dynamically create a ribbon so I would like to know how you are attaching the various commands "DocCommand", etc. to the ribbon

Bijit said...

The Custom RibbonRegionAdapter is good. I used this one. But the problem I am facing is as follows. say, 1 of my module need to show multiple ribbon tabs(Tab1 & Tab2) in the same ribbon_region when it is got loaded, not the only CarTab.

For that I have written this code,

var tab1= new Uri("Tab1", UriKind.Relative); regionManager.RequestNavigate("RibbonRegion", tab1);

var tab2= new Uri("Tab2", UriKind.Relative); regionManager.RequestNavigate("RibbonRegion", tab2);

Now the issue is, the Tab1 is getting overlaped by Tab2 and only the Lab2 is showing.

The main problem I am facing is, if I add only Tab1 the region.Views.CollectionChanged event got fired 2 times with NotifyCollectionChangedAction value Add & Reset

And if I add Tab1 & Tab2 then region.Views.CollectionChanged event got fired 2 times with NotifyCollectionChangedAction value Add & Reset (for First Tab1) and then again 2 Times (For Tab2) and the again the event is triggered with NotifyCollectionChangedAction value Remove. This is causing problem. Now this is due to the reason Tab1.KeepAlive is set to false. If I set it to True it is not removing. But I want to do some customization here. Where do I need to change?