Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

This weekend I've been having one heck of a time getting WPF Ribbon v4 working with MVVM and Prism (using unity). After much trial and error, I believe I have it working. I was hoping someone could take a look at it and give me some feedback.

RibbonRegionAdapter.cs

public class RibbonRegionAdapter : RegionAdapterBase<Ribbon>
{
    private Ribbon _ribbonTarget;

    public RibbonRegionAdapter(IRegionBehaviorFactory regionBehaviorFactory)
        : base(regionBehaviorFactory)
    {

    }

    protected override void Adapt(IRegion region, Ribbon regionTarget)
    {
        _ribbonTarget = regionTarget;

        region.Views.CollectionChanged += delegate {  
            foreach (RibbonTab tab in region.Views.Cast<RibbonTab>())  
            {  
                if (!_ribbonTarget.Items.Contains(tab))  
                {  
                    _ribbonTarget.Items.Add(tab);  
                }  
            }  
        };  
    }

    protected override IRegion CreateRegion()
    {
        return new SingleActiveRegion();
    }
}

BootStrapper.cs - To register our regionAdapter

    protected override RegionAdapterMappings ConfigureRegionAdapterMappings()
    {
        RegionAdapterMappings mappings = base.ConfigureRegionAdapterMappings();

        if (mappings != null)
        {
            mappings.RegisterMapping(typeof(Ribbon), this.Container.Resolve<RibbonRegionAdapter>());
        }


        return mappings;
    }

CarRibbonTab.xaml

<ribbon:RibbonTab x:Class="CarManager.Modules.CarModule.Views.CarRibbonTab"
               xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
             Header="Officers">
    <ribbon:RibbonGroup Header="New">

    </ribbon:RibbonGroup>
    <ribbon:RibbonGroup Header="Manage">
        <ribbon:RibbonButton Label="Make"
                                LargeImageSource="..\Resources\make.png" />
        <ribbon:RibbonButton Label="Inventory"
                                LargeImageSource="..\Resources\Inventory.png" />
        <ribbon:RibbonButton Label="Assignments" />
    </ribbon:RibbonGroup>
</ribbon:RibbonTab>

CarRibbonTab.cs - Code behind for the View

public partial class CarRibbonTab: RibbonTab
{
    public CarRibbonTab()
    {
        InitializeComponent();
    }
}

Shell.xaml - Just showing the ribbon control

<ribbon:Ribbon DockPanel.Dock="Top" Title="CarManager" prism:RegionManager.RegionName="RibbonRegion">
    <ribbon:Ribbon.ApplicationMenu>
        <ribbon:RibbonApplicationMenu SmallImageSource="Images\Icon.png">
            <ribbon:RibbonApplicationMenuItem Header="Exit"
                                              ImageSource="Images\ExitIcon.png"/>
        </ribbon:RibbonApplicationMenu>
    </ribbon:Ribbon.ApplicationMenu>

</ribbon:Ribbon>

CarModule.cs - registering the view with the region

    public class CarModule: IModule
    {
        private readonly IRegionManager  _regionManager;
        private readonly IUnityContainer _container;
        public MenuItemViewModel MenuItem;

        public CarModule(IUnityContainer container, IRegionManager regionManager)
        {
            _container     = container;
            _regionManager = regionManager;
        }

        public void Initialize()
        {
            //Ribbon
            _container.RegisterType<Object, CarRibbonTab>("CarRibbonTab");

            _regionManager.AddToRegion("RibbonRegion", _container.Resolve<CarRibbonTab>());
        }
    }
share|improve this question
    
Thanks for the code-- +1 from me. If you have worked this out, have you considered writing it up for Code Project, or a similar site. Would be very helpful to others trying to figure out this issue. –  David Veeneman Feb 14 '11 at 1:13
    
David, once I get things more ironed out I'll probably write something up for Code Project. Thank you for the reminder. –  Scott Feb 21 '11 at 14:59
    
Just wanted to let you know that I am publishing a larger article on Prism 4 apps on CodeProject, and that I used a Ribbon Region Adapter derived from your code, with acknowledgement. Thanks again. –  David Veeneman Mar 2 '11 at 16:42
    
Scott, could you please tell in which problem scenario you have used RibbonRegionAdapter, or Why we need to have one when developing Apps using Ribbon control with prism ? –  mehul9595 Jun 2 '13 at 5:55

5 Answers 5

up vote 4 down vote accepted

Not sure whether we have many Prism speacilists on CodeReview and I haven't worked with it for a while, so maybe my comments maybe incorrect at some points.

1) I do not really like the way you're handling region.Views.CollectionChanged event. This event provides a lot of information in eventArgs but you're ignoring it. Firstly you do not handle removing views at all. Secondly instead of iterating through all views every time I would use those from eventArgs (NewItems property).
2) I believe generally it is better to have views isolated from regions in terms of concrete types. Your view is not isolated since it has to inherit RibbonTab class. Maybe it is not an issue here and I'm not sure whether it should be changed somehow, it just looks strange to me.

share|improve this answer
    
Thank you for your suggestions. I'll make some changes. I'm a little confused on your point 2 however and was hoping you could provide a better explanation or an example of what you mean. –  Scott Jan 29 '11 at 23:55
    
@Scott - regarding second point. Take a look at this TabControlRegionAdapter implementation: compositewpf.svn.codeplex.com/svn/V2/trunk/CAL/Silverlight/… and especially PrepareContainerForItem method. It doesn't force views to be of type TabItem, istead it wraps them if they are not. This is correct behavior for Region IMO. But you instead forcing all you views to be inheritors of RibbonTab. It may make sense but I'm not sure it does in your scenario. –  Snowbear Jan 30 '11 at 14:12

I'm late to this party, but I'm unclear on why a custom region adapter is even required. Why can't you just use the built-in ones? To my mind all the areas in the ribbon one might want to expose already have appropriate adapters.

  • RibbonRegion => SelectorRegionAdapter (each item would be a RibbonTab)
  • RibbonTabRegion => ItemsControlRegionAdapter (each item typically a RibbonGroup)
  • RibbonApplicationMenuRegion => ItemsControlRegionAdapter (each item typically a RibbonApplicationMenuItem)
  • RibbonApplicationMenuAuxiliaryPanelRegion => ContentControlRegionAdapter
  • etcetera

I can imagine extending the built-in regions to apply custom sorting logic or the like, but your adapter does not do this.

share|improve this answer
    
Thank you for built-in ones :) –  Jalal Feb 16 '12 at 18:20

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 Tab2 is showing.

share|improve this answer

A better approach would be to build the tabs first then assign the tabs to the Content property of the hosting control. That should prevent the overlapping which I believe is caused by you making two requestnavigate calls.

share|improve this answer

Nice job, Scott. I've gotten the Ribbon working with code that follows yours pretty closely. One note for anyone else researching this issue: The modules in this application need to be WPF User Control Library projects. Simply replace the XAML in the empty UserControl objects with Scott's Ribbon Tab XAML shown above. There is no need to wrap the RibbonTab object in a UserControl.

In this specific case, I don't share Snowbear's concern about deriving the Ribbon Tab 'view' from a RibbonTab control. I agree with his point in a more general situation, but the Ribbon Tab that we are inserting into the Ribbon isn't really a view, per se. In other words, it's not a composite of several different UI controls meant to present a UI or a part of a UI to a user. The Ribbon Tab is a lot more specific than that--it is literally a RibbonTab object--a single control--and it can be nothing else.

I am probably going to include this code in a larger Prism 4 demo app that I plan to post on CodeProject. Scott, could you post a link to your writeup, so that I can reference it in my article? Thanks, and thanks for the code.

share|improve this answer
    
Offtopic -- dude, your website is hacked. –  rFactor Mar 4 '12 at 14:58

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.