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
I have the same problem, but I have to set the Icon property dynamically. The ItemsSource is a list of CommandViewModels (see http://msdn.microsoft.com/en-us/magazine/dd419663.aspx). Especially for the ribbon i wrote a RibbonCommandViewModel class:
public class RibbonCommandViewModel : CommandViewModel { #region ctor
public RibbonCommandViewModel(string displayName, ICommand command, string largeImage, string smallImage) : this(displayName, command) { this.SmallImage = smallImage; this.LargeImage = largeImage; }
#endregion
#region Properties
string largeImage; public string LargeImage { get { return largeImage; } set { if (string.Equals(largeImage, value)) return; largeImage = value; OnPropertyChanged("LargeImage"); } }
string smallImage; public string SmallImage { get { return smallImage; } set { if (string.Equals(smallImage, value)) return; smallImage = value; OnPropertyChanged("SmallImage"); } }
#endregion }
Now I setting a databinding on the UriSource property.
<BitmapImage UriSource="{Binding LargeImage}"/>
When run, the application fails with an error, "Property 'UriSource' or property 'StreamSource' must be set.
Can you help me?
Robert
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'.
Thank you for the info Andrew.