Using a XAML file as a vector Image Source
Asked Answered
D

3

22

I would like to be able to use vector graphics, preferably defined in XAML, as the Source of an Image control, just like I can currently use a raster image like a PNG. That way I could easily mix and match between bitmap and vector images, like this:

<StackPanel>
    <Image Source="Images/Namespace.png"/>
    <Image Source="Images/Module.xaml"/>
</StackPanel>

Module.xaml would most likely have <DrawingImage> as its root element instead of <UserControl>.

Actually, what I'm really going for is this, so my ViewModel could select either a raster or vector image at its discretion:

<Image Source="{Binding ImageUri}"/>

Is this possible? Can Image.Source load XAML classes from a given URI? Or is it only able to load bitmap resources?

Duky answered 10/7, 2009 at 1:57 Comment(1)
Makes me wonder... Why would using a XAML image in WPF/Silverlight be so difficult, or not supported natively... considering that WPF/Silverlight is based on XAML!Trimorphism
S
21

You can simply reference your vector graphics as StaticResources:

<Image Source="{StaticResource MyImage}" />

Store the images in a ResourceDictionary as DrawImage's. Expression Blend can help you generate this stuff:

<ResourceDictionary
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

   <DrawingImage x:Key="MyImage">
      <DrawingImage.Drawing>
         <DrawingGroup>
            <DrawingGroup.Children>
               <GeometryDrawing Brush="Black" Geometry="M 333.393,... 100.327 Z "/>
               <GeometryDrawing Brush="Black" Geometry="F1 M 202.309,... Z "/>
                      :
            </DrawingGroup.Children>
         </DrawingGroup>
     </DrawingImage.Drawing>
   </DrawingImage>

</ResourceDictionary>
Sharpeyed answered 10/7, 2009 at 9:19 Comment(2)
Sure. Doesn't help me with the databinding scenario, though (at least not directly).Duky
Simple but elegant way when combined with "Method 3" discussed in this blog postLashley
C
2

1) Add the DrawingImage.xaml to the project and set its properties to 'BuildAction=Content' and 'Copy Always'. Or else you can dynamically load the XAML from outside since the logic I am going to explain will work for loose-xaml also.

2) Write a Converter to convert the XAML uri to UIELement, in your case it will be always DrawingImage

public class FileToUIElementConverter :IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        FileStream fileStream = new FileStream((string)parameter, FileMode.Open); 
        return XamlReader.Load(fileStream) as DrawingImage;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

3) Write the XAML as below

<Window.Resources>
    <local:FileToUIElementConverter x:Key="uriToUIElementConverter"/>
</Window.Resources>
<Grid>
    <Image Stretch="Fill" Source="{Binding Converter={StaticResource uriToUIElementConverter},ConverterParameter=ImageDrawing.xaml}"/>
</Grid>
Cuckoopint answered 10/7, 2009 at 5:30 Comment(2)
I don't think FileStream can load from a compiled resource (pack:// URI), can it?Duky
There's a converter that handles resources here: https://mcmap.net/q/219176/-wpf-using-xaml-image-sourceRadian
D
1

Embed the XAML resource (DrawingImage) with type 'Resource'. It is then not a separate file and can be directly referenced via a URI, as in your original example -- BUT the URI is non-trivial. You have to figure out Microsoft's "pack" URI syntax and use that.

Duiker answered 15/10, 2009 at 22:28 Comment(1)
It isn't documented, but the "pack" URI internals are not loaded into memory until after you instantiate your first UIElement. So, trying to use it in App.cs (before your MainWindow.xaml has even been loaded) is quite frustrating. Instead, use it in your MainWindow_Load handler.Silencer

© 2022 - 2024 — McMap. All rights reserved.