Problem Creating Ribbon at Runtime

Jan 21, 2011 at 10:32 AM
Edited Jan 21, 2011 at 11:07 AM

Hi,

Since the ribbons compatibility is limited to Windows Vista and Windows 7 and I still want my application to run on earlier versions of Windows, I decided my application would have both the Ribbon and a regular Menu and Toolbars.  There will be an option for the user to switch back and forth between the Ribbon and the Menu and Toolbars.  However, the Ribbon option will only be enabled at runtime if the operating system is Windows Vista or Windows 7.

It seems the only way to do this is by creating the Ribbon at runtime, because if the Ribbon control is created at design time (placing the Ribbon control on form1 for example in the designer) the application will crash on startup if the operating system is Windows XP.  Doing this seems to work except for some really odd behaviour on the first Tab of the Ribbon.

So, creating the Ribbon at runtime seemed to work at first, until I tried placing a ComboBox on the Ribbon.  The Combox RepresentativeString property (which is used to set the physical width of the ComboBox) has no effect if the ComboBox is on the first Tab of the Ribbon.  If I switch the order of the Tabs in RibbonMarkup.xml, it doesn't matter, it's always only the first Tab that behaves this way. 

Not only the RepresentativeString has no effect, but the ItemsSourceReady has no effect either.  The only way to add items to a ComboBox on the first Tab is by calling the ItemsSourceReady event explicitly (see InitComboBoxes() in the code below). 

Furthermore, I also notice that if I try setting button images in my code (eg. _buttonDropA.LargeImage = Ribbon1.ConvertToUIImage(My.Resources.IMAGE_NAME)) the images on the first Tab don't always show up, but they do sometimes (it's intermittent).

The following is code is from Form1 of the ComboBox sample included with the library (06-ComboBox).  It's been modifed where createRibbon() is called in the Form1 load event.  If I'm doing something wrong here, please help....  I've been struggling with this for a while.  Thanks.

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

Imports RibbonLib
Imports RibbonLib.Controls
Imports RibbonLib.Controls.Events
Imports RibbonLib.Interop

Namespace _06_ComboBox
    Public Enum RibbonMarkupCommands As UInteger
        cmdButtonDropA = 1008
        cmdButtonDropB = 1009
        cmdButtonDropC = 1010
        cmdButtonDropD = 1011
        cmdButtonDropE = 1012
        cmdButtonDropF = 1013
        cmdTabDrop = 1014
        cmdGroupDrop = 1015
        cmdGroupMore = 1017
        cmdComboBox1 = 1018
        cmdComboBox2 = 1019
        cmdTabSecond = 1020
        cmdGroupSecond = 1021
        cmdComboBox3 = 1022
    End Enum

	Partial Public Class Form1
		Inherits Form
        Public _buttonDropA As RibbonButton
        Public _buttonDropB As RibbonButton
        Public _buttonDropC As RibbonButton
        Public _buttonDropD As RibbonButton
        Public _buttonDropE As RibbonButton
        Public _buttonDropF As RibbonButton
        Public _comboBox1 As RibbonComboBox
        Public _comboBox2 As RibbonComboBox
        Public _comboBox3 As RibbonComboBox

        Public _uiCollectionChangedEvent As UICollectionChangedEvent

        'Public Sub New()
        '	InitializeComponent()

        '	_buttonDropA = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropA))
        '	_buttonDropB = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropB))
        '	_buttonDropC = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropC))
        '	_buttonDropD = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropD))
        '	_buttonDropE = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropE))
        '	_buttonDropF = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropF))
        '	_comboBox1 = New RibbonComboBox(_ribbon, CUInt(RibbonMarkupCommands.cmdComboBox1))
        '          _comboBox2 = New RibbonComboBox(_ribbon, CUInt(RibbonMarkupCommands.cmdComboBox2))
        '          _comboBox3 = New RibbonComboBox(_ribbon, CUInt(RibbonMarkupCommands.cmdComboBox3))
        '          _uiCollectionChangedEvent = New UICollectionChangedEvent()

        '	AddHandler _buttonDropA.ExecuteEvent, AddressOf _buttonDropA_ExecuteEvent
        '	AddHandler _buttonDropB.ExecuteEvent, AddressOf _buttonDropB_ExecuteEvent
        '	AddHandler _buttonDropC.ExecuteEvent, AddressOf _buttonDropC_ExecuteEvent
        '	AddHandler _buttonDropD.ExecuteEvent, AddressOf _buttonDropD_ExecuteEvent
        '	AddHandler _buttonDropE.ExecuteEvent, AddressOf _buttonDropE_ExecuteEvent
        '	AddHandler _buttonDropF.ExecuteEvent, AddressOf _buttonDropF_ExecuteEvent

        '	InitComboBoxes()
        'End Sub

		Private Sub _buttonDropA_ExecuteEvent(ByVal sender As Object, ByVal e As ExecuteEventArgs)
			' get selected item index from combo box 1
			Dim selectedItemIndex As UInteger = _comboBox1.SelectedItem

			If selectedItemIndex = Constants.UI_Collection_InvalidIndex Then
				MessageBox.Show("No item is selected in simple combo")
			Else
				Dim selectedItem As Object
				_comboBox1.ItemsSource.GetItem(selectedItemIndex, selectedItem)
				Dim uiItem As IUISimplePropertySet = CType(selectedItem, IUISimplePropertySet)
				Dim itemLabel As PropVariant
				uiItem.GetValue(RibbonProperties.Label, itemLabel)
				MessageBox.Show("Selected item in simple combo is: " & CStr(itemLabel.Value))
			End If
		End Sub

		Private Sub _buttonDropB_ExecuteEvent(ByVal sender As Object, ByVal e As ExecuteEventArgs)
			' get string value from combo box 2
			Dim stringValue As String = _comboBox2.StringValue
			MessageBox.Show("String value in advanced combo is: " & stringValue)
		End Sub

		Private Sub _buttonDropC_ExecuteEvent(ByVal sender As Object, ByVal e As ExecuteEventArgs)
			' enumerate over items
			Dim itemsSource As IEnumUnknown = CType(_comboBox1.ItemsSource, IEnumUnknown)
			itemsSource.Reset()
			Dim items(0) As Object
			Dim fetchedItem As UInteger
			Do While itemsSource.Next(1, items, fetchedItem) = HRESULT.S_OK
				Dim uiItem As IUISimplePropertySet = CType(items(0), IUISimplePropertySet)
				Dim itemLabel As PropVariant
				uiItem.GetValue(RibbonProperties.Label, itemLabel)
				MessageBox.Show("Label = " & CStr(itemLabel.Value))
			Loop
		End Sub

		Private Sub _buttonDropD_ExecuteEvent(ByVal sender As Object, ByVal e As ExecuteEventArgs)
			_uiCollectionChangedEvent.Attach(_comboBox1.ItemsSource)
			AddHandler _uiCollectionChangedEvent.ChangedEvent, AddressOf _uiCollectionChangedEvent_ChangedEvent
		End Sub

		Private Sub _buttonDropE_ExecuteEvent(ByVal sender As Object, ByVal e As ExecuteEventArgs)
			Dim itemsSource1 As IUICollection = _comboBox1.ItemsSource
			Dim count As UInteger
			itemsSource1.GetCount(count)
			count += 1
			itemsSource1.Add(New GalleryItemPropertySet() With {.Label = "Label " & count.ToString(), .CategoryID = Constants.UI_Collection_InvalidIndex})
		End Sub

		Private Sub _buttonDropF_ExecuteEvent(ByVal sender As Object, ByVal e As ExecuteEventArgs)
			RemoveHandler _uiCollectionChangedEvent.ChangedEvent, AddressOf _uiCollectionChangedEvent_ChangedEvent
			_uiCollectionChangedEvent.Detach()
		End Sub

		Private Sub _uiCollectionChangedEvent_ChangedEvent(ByVal sender As Object, ByVal e As UICollectionChangedEventArgs)
			MessageBox.Show("Got ChangedEvent. Action = " & e.Action.ToString())
		End Sub

        Private Sub InitComboBoxes()
            _comboBox1.RepresentativeString = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ' THIS HAS NO EFFECT
            _comboBox2.RepresentativeString = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ' THIS HAS NO EFFECT
            _comboBox3.RepresentativeString = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" ' THIS WORKS

            _comboBox1.Label = "Simple Combo"
            _comboBox2.Label = "Advanced Combo"
            _comboBox3.Label = "Another Combo"

            AddHandler _comboBox1.ItemsSourceReady, AddressOf _comboBox1_ItemsSourceReady
            AddHandler _comboBox2.ItemsSourceReady, AddressOf _comboBox2_CategoriesReady
            AddHandler _comboBox2.ItemsSourceReady, AddressOf _comboBox2_ItemsSourceReady
            AddHandler _comboBox3.ItemsSourceReady, AddressOf _comboBox3_ItemsSourceReady

            ' HAVE TO CALL THE FOLLOWING METHODS TO ADD ITEMS TO COMBOBOX1 AND COMBOBOX2
            Call _comboBox2_CategoriesReady()
            Call _comboBox2_ItemsSourceReady()
            Call _comboBox1_ItemsSourceReady()
        End Sub

        Private Sub _comboBox1_ItemsSourceReady()
            ' set combobox1 items
            Dim itemsSource1 As IUICollection = _comboBox1.ItemsSource
            itemsSource1.Clear()
            itemsSource1.Add(New GalleryItemPropertySet() With {.Label = "Label 1", .CategoryID = Constants.UI_Collection_InvalidIndex})
            itemsSource1.Add(New GalleryItemPropertySet() With {.Label = "Label 2", .CategoryID = Constants.UI_Collection_InvalidIndex})
            itemsSource1.Add(New GalleryItemPropertySet() With {.Label = "Label 3", .CategoryID = Constants.UI_Collection_InvalidIndex})
        End Sub

        Private Sub _comboBox2_CategoriesReady()
            ' set _comboBox2 categories
            Dim categories2 As IUICollection = _comboBox2.Categories
            categories2.Clear()
            categories2.Add(New GalleryItemPropertySet() With {.Label = "Category 1", .CategoryID = 1})
            categories2.Add(New GalleryItemPropertySet() With {.Label = "Category 2", .CategoryID = 2})
        End Sub

        Private Sub _comboBox2_ItemsSourceReady()
            ' set _comboBox2 items
            Dim itemsSource2 As IUICollection = _comboBox2.ItemsSource
            itemsSource2.Clear()
            itemsSource2.Add(New GalleryItemPropertySet() With {.Label = "Label 1", .CategoryID = 1})
            itemsSource2.Add(New GalleryItemPropertySet() With {.Label = "Label 2", .CategoryID = 1})
            itemsSource2.Add(New GalleryItemPropertySet() With {.Label = "Label 3", .CategoryID = 2})
        End Sub

        Private Sub _comboBox3_ItemsSourceReady()
            ' set combobox3 items
            Dim itemsSource3 As IUICollection = _comboBox3.ItemsSource
            itemsSource3.Clear()
            itemsSource3.Add(New GalleryItemPropertySet() With {.Label = "Label 1", .CategoryID = Constants.UI_Collection_InvalidIndex})
            itemsSource3.Add(New GalleryItemPropertySet() With {.Label = "Label 2", .CategoryID = Constants.UI_Collection_InvalidIndex})
            itemsSource3.Add(New GalleryItemPropertySet() With {.Label = "Label 3", .CategoryID = Constants.UI_Collection_InvalidIndex})
        End Sub

        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Call createRibbon()
        End Sub

        Public _ribbon As Ribbon
        Sub createRibbon()
            '============================BELOW code is from designer========================================
            Me._ribbon = New RibbonLib.Ribbon()
            '
            '_ribbon
            '
            Me._ribbon.Location = New System.Drawing.Point(0, 0)
            Me._ribbon.Minimized = False
            Me._ribbon.Name = "_ribbon"
            Me._ribbon.ResourceName = "RibbonMarkup.ribbon"
            Me._ribbon.ShortcutTableResourceName = Nothing
            Me._ribbon.Size = New System.Drawing.Size(712, 100)
            Me._ribbon.TabIndex = 2


            Me.Controls.Add(Me._ribbon)
            '============================ABOVE code is from designer========================================

            'Private _ribbon As RibbonLib.Ribbon
            _buttonDropA = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropA))
            _buttonDropB = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropB))
            _buttonDropC = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropC))
            _buttonDropD = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropD))
            _buttonDropE = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropE))
            _buttonDropF = New RibbonButton(_ribbon, CUInt(RibbonMarkupCommands.cmdButtonDropF))
            _comboBox1 = New RibbonComboBox(_ribbon, CUInt(RibbonMarkupCommands.cmdComboBox1))
            _comboBox2 = New RibbonComboBox(_ribbon, CUInt(RibbonMarkupCommands.cmdComboBox2))
            _comboBox3 = New RibbonComboBox(_ribbon, CUInt(RibbonMarkupCommands.cmdComboBox3))
            _uiCollectionChangedEvent = New UICollectionChangedEvent()

            AddHandler _buttonDropA.ExecuteEvent, AddressOf _buttonDropA_ExecuteEvent
            AddHandler _buttonDropB.ExecuteEvent, AddressOf _buttonDropB_ExecuteEvent
            AddHandler _buttonDropC.ExecuteEvent, AddressOf _buttonDropC_ExecuteEvent
            AddHandler _buttonDropD.ExecuteEvent, AddressOf _buttonDropD_ExecuteEvent
            AddHandler _buttonDropE.ExecuteEvent, AddressOf _buttonDropE_ExecuteEvent
            AddHandler _buttonDropF.ExecuteEvent, AddressOf _buttonDropF_ExecuteEvent

            InitComboBoxes()
        End Sub
    End Class
End Namespace
Jan 25, 2011 at 7:46 AM
Edited Jan 25, 2011 at 7:49 AM

Hi,

you should add two Form classes to your project. Create one with Ribbon, one with Toolbar. You can use the Designer for this. Then, define an interface and implement it in your Forms. On startup you can define which Form you want to use.

 

Inheritance of the Form would be another option here...

-          MainForm

-          - RibbonMainForm

-          - ToolbarMainForm

 

Thanks

Bernhard

Mar 4, 2011 at 2:13 PM

Hi Adamata

I like to know if you can share your idea.

How you create menu ribbon at runtime?

I like to know, because I have a application when user logs to the system the menu ribbon load the options according to the role of the user.

Regards

Ricardo

Apr 5, 2011 at 6:31 PM
Edited Apr 5, 2011 at 6:32 PM

Hi raranibar,

Sorry it took so long to respond, I've been really busy with other none computer stuff (disc golf).  Anyway, the way I tried to create a ribbon at runtime is demonstrated in the long code above.  However, I had a few problems when I tried this.  One of those problems being that I couldn't change the physical size of the ComboBox control which was completely unacceptable.  So, I decided this was a bad approach and decided instead to create the ribbon the normal way (in the designer).  With this method, I simply hide and un-hide the ribbon using the RibbonViewable property.  After hiding the ribbon, I make a regular menu and toolbar visible allowing the user to choose between the two.

I doubt this will help you either way.  Since it seems maybe you want to change buttons and other controls on the ribbon according to a particular user that logs in.  Even when I was trying to create the actual ribbon itself at runtime, the actual ribbon controls were already laid out in the Ribbon.xml file.

Sorry again that I couldn't be more help.  I would be interested in hearing about your progress if you should happen to pursue this.

Good luck, raranibar.