Thursday, February 26, 2009

Creating RibbonTab programatically

I've spent several hours on this issue so it's worth document it just in case it might help someone out there...

When using CWPF (aka Prism) in combintation with the RibbonControlsLibrary I was having a weird problem that my RibbonTabs created "inside" the Prism Modules where loosing it's bindign context and therefore the icon/text was gone (the 2nd time).


Both  Bartek Szafko and Joachim Kerschbaumer articles explain very nicely how to create adapter to be able to use RibbonTabs inside CWPF. I am not going to talk about that in this entry so please read them before in case you are just starting with the RibbonControlsLibrary .

My problem is that each of the RibbonTabs created inside CWPF IModule is also driven by a ViewModel. 

  public partial class DynamicTab 
    {
        public DynamicTabVM ViewModel { get; private set; }

        public DynamicTab()
        {
            InitializeComponent();
            DataContext = ViewModel= new DynamicTabVM();
        }

The technique of re-attaching the RibbonTab works fine if there is no databinding or it's using static resources.

In my scenario all the RibbonButtons have a Bindingg against an ICommand in the viewModel.
                     
When "switching" between Ribbon Tabs --> the DataContext was gone for the "dynamic" RibbonTab. 

I COULD not solve the problem by changing the binding to RelativeSource. Probably this is because I am new to WPF binding and the IDE (vs.net 2008) does not really help at all here.


      private void AddDynamicTabs()
        {
            //Create the Tab.
            var dynamicTab = new DynamicTab();

            // The tab DataContext is the ViewModel.
            var vm = (DynamicTabVM) dynamicTab.DataContext;

            // Take the included ribbon tab.
            RibbonTab tab = dynamicTab.DynamicRibbonTab;
            
            // Disconnect from container
            dynamicTab.Content = null;

            // Re-assign the DataContext
            tab.DataContext = vm;


            foreach (var group in tab.Groups)
            {
                group.DataContext = vm;

                foreach (var control in group.Controls)
                {
                    if (control is RibbonButton)
                    {
                        (control as RibbonButton).DataContext = vm;
                    }
                    // TODO : Applies to more controls.. We are currently using RibbonButton.
                }
            }

            MyRibbon.Tabs.Add(tab);

            // This is needed to be able to view the NEW tab using the correct Style/Skin.
            MyRibbon.InvalidateVisual();

        }


You can download the Example code.

The example is not actually using CWPF and therefore this code should be included in the Adapter.