Correctly sized icon bound to Canvas object
I need to follow a method that retrieves an object Canvas
from the Resource Dictionary using a named collection and a relative URI, and links Canvas
to MenuItem
Icon
. This code for getting vector graphics Canvas
is
public Canvas GetVectorGraphic(string assemblyName, string relativeUri, string name)
{
var imageResourceDictionary = new ResourceDictionary();
imageResourceDictionary.Source =
new Uri(assemblyName + ";component/" + relativeUri, UriKind.Relative)
?? new Uri(relativeUri, UriKind.Relative);
if (imageResourceDictionary.Source == null)
return default(Canvas);
return imageResourceDictionary[name] as Canvas;
}
Linking to my MenuItem
-
<Style x:Key="MenuItem" TargetType="{x:Type Controls:MenuItemEx}">
<Setter Property="Icon">
<Setter.Value>
<Image Source="{Binding IconSource}" Width="16" Height="16"/>
</Setter.Value>
</Setter>
...
I also tried
<Setter Property="Icon">
<Setter.Value>
<Rectangle Width="16" Height="16">
<Rectangle.Fill>
<VisualBrush Stretch="Uniform"
Visual="{Binding IconSource}"/>
</Rectangle.Fill>
</Rectangle>
</Setter.Value>
</Setter>
You can see that I am trying to set the height Canvas
to 16 x 16 directly and also by reverting to filling the size rectangle, but that doesn't work - it just results in a blank image. If I do not specify the specifications Height
and Width
, the resulting graphics are too large.
I also tried resizing Canvas
when I read it from the dictionary via
...
Canvas c = imageResourceDictionary[name] as Canvas;
c.Height = 16;
c.Width = 16;
return c;
But this leads to the disappearance of the image.
How do I properly resize my object Canvas
to fit mine MenuItem
?
Edit ( Partial answer ):
I came across many posts, but none of them resolved all the problems I had in one post. Problems:
- Do not receive images using vector graphics. [Solved]
- Retrieving images, but not properly scaled. [Solved]
- Getting images scaled and displayed, but only one at a time. [Solved]
- Imaged is scaled and rendered for all required MenuItems, but is aware that top-level menu items have unwanted headroom. [ON GOING]
The way I solved everything but the last problem was 1. use the correct image source for the vector graphics, in which case I found that filling the rectangle did the job. 2. You can bind to the Icon object directly to get images, but there is no real way to scale them accordingly. 3. You can scale images with a rectangle by setting Width
and Height
and filling this with VisualBrush
, but this aligns the resource amongst MenuItems
so only one will be displayed. To get Icons to be unseparated, you need to create a static resource and install x:Shared="False"
. The final XAML looks like
<Rectangle x:Key="MenuItemIcon" x:Shared="False"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Width="16" Height="16">
<Rectangle.Fill>
<VisualBrush Stretch="Uniform" Visual="{Binding IconSource}"/>
</Rectangle.Fill>
</Rectangle>
<Style x:Key="MenuItem" TargetType="{x:Type Controls:MenuItemEx}">
<Setter Property="Icon" Value="{StaticResource MenuItemIcon}"/>
<Setter Property="InputGestureText" Value="{Binding InputGestureText}"/>
<Setter Property="Caliburn:Action.Target" Value="{Binding}"/>
<Setter Property="Caliburn:Message.Attach" Value="{Binding ActionText}"/>
</Style>
Outstanding problem
Now I have a problem where top-level items are also offset to the right (shown by the red arrow below) because the dimensions of the rectangle are hardcoded to 16. However, snapping to Witdh
and Height
seems to make the image disappear again ...
Now I will try to create a menu item template and set the icon area to auto-fail. Any other solutions are appreciated ...
source to share
The two main problems were that the icons are split when not contained in an external static container (see edit question). The way I got it all to work in the end is using the following XAML:
<Rectangle x:Key="MenuItemIcon" x:Shared="False"
Visibility="{Binding IconVisibility}"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
Width="16" Height="16">
<Rectangle.Fill>
<VisualBrush Stretch="Uniform" Visual="{Binding IconSource}"/>
</Rectangle.Fill>
</Rectangle>
<Style x:Key="MenuItem" TargetType="{x:Type Controls:MenuItemEx}">
<Setter Property="Icon" Value="{StaticResource MenuItemIcon}"/>
<Setter Property="InputGestureText" Value="{Binding InputGestureText}"/>
<Setter Property="Caliburn:Action.Target" Value="{Binding}"/>
<Setter Property="Caliburn:Message.Attach" Value="{Binding ActionText}"/>
</Style>
If the Visibility
default is MainMenuIcon
set to Visibility.Collapsed
. This provides the following kind of menu ...
source to share
Viewbox
can easily take care of such things by scaling the content to an accessible size
de-size the image and place the image inside the viewport
Example
<Setter Property="Icon">
<Setter.Value>
<Viewbox>
<Image Source="{Binding IconSource}" />
</Viewbox>
</Setter.Value>
</Setter>
if you want to limit the size available, maybe you can apply the size in the viewport
eg,
<Viewbox Width="16" Height="16">
from MSDN: viewport
A Viewbox defines a content decorator that can stretch and scale a single child to fill the available space.
source to share