My ribbon's application menu has several MenuTools in it. I was previously manually populating all those MenuItems with ButtonTools using procedural code, and was seeing proper results. The menus and buttons all looked good, like in Example 1 in my attached image.
I needed to switch to a binding approach to simplify all the internal wiring, so I converted to pure XAML for adding and populating these MenuTools in my application menu. I used an ImageSource to bind the MenuTool items to collections in my ViewModel, and used a DataTemplate specifying a ButtonTool for the MenuTool items.
Unfortunately the results aren't the same in the bound approach. The entire button content lives only in the very center of the MenuTool item. It's not using the LargeImage, and you have to click on that central button content to actually press the button. Ick.
Here's some XAML that manually adds a ButtonTool to a MenuTool, which gives the nice results like you see in Example 1 in my attached image:
<igRibbon:MenuTool Id="MyAccountMenu" Caption="My Account" LargeImage="/images/MyAccount_32.png"> <igRibbon:ButtonTool Id="ChangeXperiencePasswordButton" Caption="Change Xperience Password" SmallImage="/images/Key_16.png" LargeImage="/images/Key_32.png" Click="ChangeXperiencePasswordButton_Click" /></igRibbon:MenuTool>
Here's some XAML that shows the binding approach. This gives the icky results like you see in Example 2 in my attached image:
<igRibbon:MenuTool Id="SelectThemeMenu" Caption="Select Theme" LargeImage="/images/ThemePalette_32.png" UseLargeImages="True" ItemsSource="{Binding Themes}"> <igRibbon:MenuTool.ItemTemplate> <DataTemplate> <igRibbon:ButtonTool Caption="{Binding Path=Name}" SmallImage="/images/ThemePalette_16.png" LargeImage="/images/ThemePalette_32.png" Tag="{Binding}" Click="SelectThemeButton_Click" /> </DataTemplate> </igRibbon:MenuTool.ItemTemplate></igRibbon:MenuTool>
I'm not sure why manually adding a ButtonTool as the child of a MenuTool works, while specifying a ButtonTool as the DataTemplate for a MenuTool doesn't.
I feel like I must be missing something simple here. Please tell me I don't have to fall back on procedural code to make this work! :)
Thanks for your help,Jim Honeycutt
The approach that you are using will not work. Essentially the way that the menutool works is that it creates a ToolMenuItem for each item. The toolmenuitem is then initialized based on the item. If that item is a tool like a button then its content is bound to that of the menu item. In your case however, the item is some arbitrary object. So the Header of the menuitem is set to that item. The contentpresenter bound to that property then uses the itemtemplate to create some elements that it will host - a button tool in this case. So that button tool has no direct association with the toolmenuitem and therefore is just shown as a button within the menu item. What you probably want to do is to provide an ItemContainerStyle for ToolMenuItem that provides the image and uses a command (rather than hooking an event) and then just use the ItemTemplate to provide the actual content for the menu item - e.g. a textblock that binds to the Name. e.g.
Hi Andrew!
Is there a way to bind the Icon too? I tried something like:
<igRibbon:MenuTool.ItemContainerStyle> <Style TargetType="{x:Type igRibbon:ToolMenuItem}"> <Setter Property="igRibbon:ToolMenuItem.Icon"> <Setter.Value> <Image Source="{Binding ImageKey, Converter={StaticResource ImageResourceConverter}, Mode=OneWay}" /> </Setter.Value> </Setter> </Style></igRibbon:MenuTool.ItemContainerStyle>
(ImageResourceConverter is responsible for Icon-to-BitmapSource conversion)
When using the above Style, I get the following exception:
Cannot add content of type 'System.Windows.Controls.Image' to an object of type 'System.Object'.
ahhh... sorry I missed the DataTemplate at the top.
Image is a UIElement. You can't set the value of a setter to an element instance since the style can be used for multiple instances and each would need its own element instance (i.e. something normally provided by a template/frameworkelementfactory). In the sample code I provided I set the Icon to an ImageSource (specifically a BitmapImage) and used a DataTemplate to create an Image element that would display the imagesource so I suspect you would have to do the same thing. Expose a property of type ImageSource and bind the Icon property to that and have a datatemplate for ImageSource.