-1

I'm trying to get a reusable SVG image into WPF.

I have a merged dictionary which contains an entry for an external xaml file which contains a canvas, which in turn came from an SVG file. It has a structure like:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Canvas x:Key="myImage" Name="myImage" Width="110" Height="35">
        <Canvas.RenderTransform>
            <TranslateTransform X="0" Y="0"/>
        </Canvas.RenderTransform>
        <Canvas.Resources/>
        <Canvas Name="layer1">
            <Canvas.RenderTransform>
                <TranslateTransform X="-51.393708" Y="-16.078911"/>
            </Canvas.RenderTransform>
            <Ellipse...

Note the Canvas width and height are specified here.

To get this to appear in a Window, I add this to my window's resources:

<ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="XamlResources/myImage.xaml"/>
</ResourceDictionary.MergedDictionaries>
...
<Viewbox Width="200" Stretch="Uniform" HorizontalAlignment="Left">
    <Canvas Width="110"  Height="35">
        <StaticResource ResourceKey="myImage"/>
    </Canvas>
</Viewbox>

Note that the Canvas width and height are again specified here.

My question is, why do I need to specify the canvas size (110x35) in both the resource and the window control? If I remove the one in the window to have:

<Canvas Width="110"  Height="35">
    <StaticResource ResourceKey="myImage"/>
</Canvas>

...then the image disappears.

Am I doing something fundamentally wrong with trying to get a reusable SVG image into WPF?

Geoff
  • 8,551
  • 1
  • 43
  • 50
  • why do you even need the second Canvas? you can just put resource to ViewBox directly with the same code. though this is not the optimal way to have vector images in WPF – ASh Mar 23 '23 at 21:11
  • "*Am I doing something fundamentally wrong with trying to get a reusable SVG*" - I'd say yes. Instead of Canvas and Ellipse and other UI elements, an SVG should be converted to a set of Drawings that would be visualized by a DrawingBrush or a DrawingImage. See for example [WPF What is the correct way of using SVG files as icons in WPF](https://stackoverflow.com/questions/3526366/wpf-what-is-the-correct-way-of-using-svg-files-as-icons-in-wpf) – Clemens Mar 23 '23 at 21:20
  • @ASh If I remove the canvas in the Window, I get `Specified element is already the logical child of another element. Disconnect it first.` Which I have a hard time decoding, even after searching. – Geoff Mar 23 '23 at 21:26
  • @Clemens I already had the image in Inkscape, so after some searching I followed [this answer](https://stackoverflow.com/a/29637137/55487). In your linked answer, the section labelled "Using a Canvas as an icon" is what I thought I _was_ doing? Just as a resource, and inside a ViewBox instead of a button. How would you recommend I do it differently? – Geoff Mar 23 '23 at 21:31
  • The problem with UIElements as resources is that resources are shared by default, and you can not use a single UIElement at more than one place in a visual tree. While you may get around this limitation by setting `x:Shared="False"` on the resource, it would still be better to use Drawings or Geometries as resources. Or perhaps use the Canvas with a VisualBrush. – Clemens Mar 23 '23 at 21:36

1 Answers1

0

Note that the Canvas width and height are again specified here.

No, you are creating a new Canvas that wraps the other one that is defied your resource dictionary.

If you want to use the myImage resource directly, you should reference it like this:

<StaticResource ResourceKey="myImage"/>

Then you don't need to specify the size more than once.

But to be able to reuse the resource in more than one place, you should set the x:Shared attribute of the resource to false to prevent the same Canvas instance form being reused:

<Canvas x:Key="myImage" x:Shared="false" ... />
mm8
  • 163,881
  • 10
  • 57
  • 88
  • Thanks! This solved it for me. I do understand the comments to my post about not using UIElements as resources, but I couldn't find any way to avoid this. I assume I needed to combine the different elements (Ellipse, TextBlock, Path) into one drawing structure, but I couldn't see how to do this without it becoming a large amount of work to update every time the source SVG changed. Even when I reduced them to multiple paths in Inkscape, they still all had different fill and stroke information. – Geoff Mar 28 '23 at 01:52