views:

181

answers:

2

I have several menu items like this:

<navigation:RadMenuItem Header="New Assignment">
    <navigation:RadMenuItem.Icon>
        <Image Source="/Images/New_Assignment.jpeg" Width="20" Height="20" />
    </navigation:RadMenuItem.Icon>
</navigation:RadMenuItem>
<navigation:RadMenuItem Header="New Course">
    <navigation:RadMenuItem.Icon>
        <Image Source="/Images/New_Course.jpeg" Width="20" Height="20" />
    </navigation:RadMenuItem.Icon>
</navigation:RadMenuItem>
<navigation:RadMenuItem Header="New Folder">
    <navigation:RadMenuItem.Icon>
        <Image Source="/Images/New_Folder.jpeg" Width="20" Height="20" />
    </navigation:RadMenuItem.Icon>
</navigation:RadMenuItem>

Notice that I have to set the icon for each Item. (All the icons are in the /Images/ folder) So how can I pass a parameter so that maybe I could say:

<navigation:RadMenuItem Header="New Assignment" Icon="{Binding ImageCollection, param1=New_Assignment.jpeg}" />

Where ImageCollection is the collection of images in the /Images/ folder.

A: 

I think the ideal way would be to use a databound ListBox bound to a collection of Naviation menu items:

<ListBox DataContext="{Binding MyCollectionOfNavigationItems}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <navigation:RadMenuItem Header="{Binding Header}" Icon="{Binding ImagePath, Converter={StaticResource PathToImageConverter}}"
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

and binding it to a collection of items that might be structured something like this:

public class NavigationItem {
    public string Header { get; set; }
    public string ImagePath { get; set; }
}

and using a custom converter to convert the image path to an image (you also could simply have an image property that you create in code).

If that's not an option you could probably do it using a MultiBinding and an attached property, but if you're still writing out the MultiBinding syntax for each item, that would be even more verbose.

jeffora
+2  A: 

There is a solution to your problem.

You use a dictionary of type < string, ImageSource> as your ImageCollection variable like so:

public Dictionary< string, ImageSource> ImageCollection{ get; set; }

Now to construct your collection, you must specify the correct ImageSource with a valid URI.

You start with your base address, in your case "/Images" so that you can change your base address at one point of your code instead of having to look for all occurrences of image address... just for convenience.

const readonly string BASE_ADDR = "/Images";

Now you can begin to build your image collection like so:

ImageCollection = new Dictionary< string, ImageSource>
{
    { "New_Assignment", new BitmapImage(BASE_ADDR + "/New_Assignment.jpeg") }
    ...
    ...
}

Now in your XAML, you are able to bind like this:

<navigation:RadMenuItem
  Header="New Assignment"
  Icon="{Binding ImageCollection[New_Assignment]}" />

This should work nicely. Happy coding.

Tri Q
Thanks! That did the trick. But I have only one more problem: I have to manually size the images to 20 width and 20 height. How can I set the image's width and height properties. Maybe like: public Dictionary<string, ImageSource, Size> ImageCollection { get; set; }?
Mohit Deshpande
Unfortunately Dictionary only works with paired tuples, so you could not add a third one even if you wanted to. This is the limitation of C# that collections can only be indexed by one element. Manually setting the size for an image may be a good thing in the long run... sometimes you can't get away with everything =P
Tri Q
Could ImageSource be replaced with like Icon?
Mohit Deshpande
You can store anything you like in the dictionary.
Tri Q