1
votes

In a WPF client application, I'm having some difficulties using hierarchical data template to load databound menuitems.

First I created the ViewModel, containing the basic properties for a menu item : Title, Command, ImageSource (Path to the image to use for Icon property) and sub items.

Then, I created the view in a XAML window to display my menus. To bind my collection, taking sub items into account, I used the hierarchical data template for the menu item template.

Here is the XAML code for the ItemTemplate :

<HierarchicalDataTemplate DataType="{x:Type vm:MenuItemViewModel}" ItemsSource="{Binding Path=Items}">
    <HierarchicalDataTemplate.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Style.Resources>
                <Image x:Key="ItemImage" Source="{Binding ImageSource}" Width="16" Height="16" x:Shared="false" />
            </Style.Resources>
            <Style.Setters>
                <Setter Property="Command" Value="{Binding Command}" />
                <Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
                <Setter Property="Icon" Value="{StaticResource ItemImage}" />
            </Style.Setters>
        </Style>
    </HierarchicalDataTemplate.ItemContainerStyle>
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Title}" />
    </StackPanel>
</HierarchicalDataTemplate>

When I initialize the menus and show the window, all looks fine.

After that, I tried to put the menu item template into a resource dictionary in order to be able to reuse it from wherever in my application as a default template. When I do that, I have an exception thrown :

Shared attribute in namespace 'http://schemas.microsoft.com/winfx/2006/xaml' can be used only in compiled resource dictionaries.

After spending so much time searching for a solution, I finally made a tester project (available here) to demonstrate the problem.

I don't know how to make my resource dictionary being a compiled resource dictionary... Could anyone help me ?

2

2 Answers

0
votes

Try removing x:Shared="false" from the <Image> element

0
votes

Solution was found, implementing a converter :

public class MenuIconConverter : IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null) return Binding.DoNothing;

        string imageUri = value.ToString();

        if (string.IsNullOrEmpty(imageUri)) return Binding.DoNothing;

        BitmapImage bitmapImage = new BitmapImage(new Uri(imageUri, UriKind.RelativeOrAbsolute)) { DecodePixelHeight = 16, DecodePixelWidth = 16 };

        return new Image() { Height = 16, Width = 16, Source = bitmapImage, SnapsToDevicePixels = true, UseLayoutRounding = true };
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return Binding.DoNothing;
    }

    #endregion
}

To use the converter, DataTemplate should be modified :

<converter:MenuIconConverter x:Key="MenuIconConverter" />

<HierarchicalDataTemplate x:Key="MenuItemTemplate" DataType="{x:Type vm:MenuItemViewModel}" ItemsSource="{Binding Path=Items}">
    <HierarchicalDataTemplate.ItemContainerStyle>
        <Style TargetType="MenuItem">
            <Style.Setters>
                <Setter Property="Command" Value="{Binding Command}" />
                <Setter Property="CommandParameter" Value="{Binding CommandParameter}" />
                <Setter Property="Icon" Value="{Binding ImageSource, Converter={StaticResource MenuIconConverter}, Mode=OneWay}" />
            </Style.Setters>
        </Style>
    </HierarchicalDataTemplate.ItemContainerStyle>
    <TextBlock Text="{Binding Title}" />
</HierarchicalDataTemplate>

With this, all work fine. I was expecting solution with no code behind, but it seems not to be possible :(