Search code examples
c#wpfribbon

How to add or remove item from RibbonGroup


I have a Ribbon, in which I have some kind of tabs. On one tab I have two RibbonGroups. What I want to achieve is when I click RibbonMenuButton located in RibbonGroup (first), I want to add some item (eg other RibbonMenuButton) to the RibbonGroup no 2. How can I achieve this with C#?

<Custom:Ribbon Name="RibbonMenu" HorizontalAlignment="Stretch" VerticalAlignment="Top" Loaded="RibbonLoaded" Grid.Row="0">
        <Custom:Ribbon.ApplicationMenu>
            <Custom:RibbonApplicationMenu KeyTip="F">
            </Custom:RibbonApplicationMenu>
        </Custom:Ribbon.ApplicationMenu>
        <Custom:RibbonTab Header="Home" KeyTip="H" >
            <Custom:RibbonGroup x:Name="ClipboardGroup" Header="Home">
            </Custom:RibbonGroup>
            <Custom:RibbonGroup x:Name="ConnectionGroup" Header="Connect">          
            </Custom:RibbonGroup>
        </Custom:RibbonTab>
        <Custom:RibbonTab Header="Script">
            <Custom:RibbonGroup x:Name="ScriptsGroup" Header="Scripts">
            </Custom:RibbonGroup>
        </Custom:RibbonTab>
        <Custom:RibbonTab Header="Charts">
            <Custom:RibbonGroup x:Name="chartsGroup" Header="Charts">
                <Custom:RibbonMenuButton Label="First Chart" Name="firstChart" LargeImageSource="Resources/chartIco.png" PreviewMouseLeftButtonDown="firstChart_MouseLeftButtonDown"/>
                <Custom:RibbonMenuButton Label="Second Chart" Name="secondChart" LargeImageSource="Resources/chartIco.png" PreviewMouseLeftButtonDown="secondChart_MouseLeftButtonDown"/>
            </Custom:RibbonGroup>
            <Custom:RibbonGroup x:Name="chartsTools" Header="Tools">
            </Custom:RibbonGroup>
        </Custom:RibbonTab>
</Custom:Ribbon>

This is sample of my code. What I want to achive is when I click RibbonMenuItem fron "chartsGroup" RibbonGroup, I want to add items (checkboxex, textboxes etx.) to the chartsTools RibbonGroup.


Solution

  • Since the controls that are to be displayed are always the same, the easiest approach would be to just add them in XAML and set their Visibility to Collapsed.

    Then you either use RibbonMenuButton.MouseLeftButtonUp or RibbonMenuButton.MouseLeftButtonDown EventHandler or use the Command pattern (if you're using MVVM or something alike).

    Inside the Command/EventHandler you then set the Visibility of the controls that are relevant to the selected RibbonMenuButtonto Visible and the Visibility of the irrelevant controls to Collapsed.

    In MVVM you'd have to bind the Visibility of the affected controls to something on your ViewModel, maybe a boolean (in that case you need a boolean/Visibility converter), and set those bools from your Command.

    If you'd be using a ToggleButton instead of those RibbonMenuButtons you could also directly bind the Visibility of the controls to the Toggled state of the responsibile ToggleButton, of course you'd need a converter again. Or bind to the Enabled state, if you'd rather have them greyed out.

    ===================================

    For a more modular approach, you've two possibilities:

    1. Go with the above method, but add if statements when changing the Visibility to Visible. I'm not sure how you'd determine which functionalities to enable, but that should handle all possible situations as long as all features are always inside the main program and you just don't want to always show all functions.
    2. Use dependency injection (easiest to set up is probably MEF). Put 'extra' methods and their WPF controls in seperate MEF modules. You also need at least one interface, best to put it in a third assembly that is then referenced by the modules and your main program. On startup use ImportMany to load all modules, then go through that list with a foreach loop and get the WPF controls from those modules. I think you'd need two or three methods that are defined in the interface for that:
      • one method to get the actual Ribbon control that needs to be added to a RibbonGroup
      • one method that returns something to determine where that control goes (in which group/which position), this may need to be split into two methods, if you want to specify a group and a position inside that group
      • optional: A method that allows you to set the current object for that module. So if the user selects an object on which he/she wants to work, you need to let every module know which object that is. Either you let your main program set that object on every module when the object is being changed OR you create a second interface that is implemented by your main program and use an Import on your modules for that interface. Inside the module's eventhandler/command you can then query the main program for the current object.