Can someone describe a recommended Step by Step procedure for doing this?
Step1. Convert SVG to XAML... thats easy
Step2. Now what?
Your technique will depend on what XAML object your SVG to XAML converter produces. Does it produce a Drawing? An Image? A Grid? A Canvas? A Path? A Geometry? In each case your technique will be different.
In the examples below I will assume you are using your icon on a button, which is the most common scenario, but note that the same techniques will work for any ContentControl.
Using a Drawing as an icon
To use a Drawing, paint an approriately-sized rectangle with a DrawingBrush:
<Button>
<Rectangle Width="100" Height="100">
<Rectangle.Fill>
<DrawingBrush>
<DrawingBrush.Drawing>
<Drawing ... /> <!-- Converted from SVG -->
</DrawingBrush.Drawing>
</DrawingBrush>
</Rectangle.Fill>
</Rectangle>
</Button>
Using an Image as an icon
An image can be used directly:
<Button>
<Image ... /> <!-- Converted from SVG -->
</Button>
Using a Grid as an icon
A grid can be used directly:
<Button>
<Grid ... /> <!-- Converted from SVG -->
</Button>
Or you can include it in a Viewbox if you need to control the size:
<Button>
<Viewbox ...>
<Grid ... /> <!-- Converted from SVG -->
</Viewbox>
</Button>
Using a Canvas as an icon
This is like using an image or grid, but since a canvas has no fixed size you need to specify the height and width (unless these are already set by the SVG converter):
<Button>
<Canvas Height="100" Width="100"> <!-- Converted from SVG, with additions -->
</Canvas>
</Button>
Using a Path as an icon
You can use a Path, but you must set the stroke or fill explicitly:
<Button>
<Path Stroke="Red" Data="..." /> <!-- Converted from SVG, with additions -->
</Button>
or
<Button>
<Path Fill="Blue" Data="..." /> <!-- Converted from SVG, with additions -->
</Button>
Using a Geometry as an icon
You can use a Path to draw your geometry. If it should be stroked, set the Stroke:
<Button>
<Path Stroke="Red" Width="100" Height="100">
<Path.Data>
<Geometry ... /> <!-- Converted from SVG -->
</Path.Data>
</Path>
</Button>
or if it should be filled, set the Fill:
<Button>
<Path Fill="Blue" Width="100" Height="100">
<Path.Data>
<Geometry ... /> <!-- Converted from SVG -->
</Path.Data>
</Path>
</Button>
How to data bind
If you're doing the SVG -> XAML conversion in code and want the resulting XAML to appear using data binding, use one of the following:
Binding a Drawing:
<Button>
<Rectangle Width="100" Height="100">
<Rectangle.Fill>
<DrawingBrush Drawing="{Binding Drawing, Source={StaticResource ...}}" />
</Rectangle.Fill>
</Rectangle>
</Button>
Binding an Image:
<Button Content="{Binding Image}" />
Binding a Grid:
<Button Content="{Binding Grid}" />
Binding a Grid in a Viewbox:
<Button>
<Viewbox ...>
<ContentPresenter Content="{Binding Grid}" />
</Viewbox>
</Button>
Binding a Canvas:
<Button>
<ContentPresenter Height="100" Width="100" Content="{Binding Canvas}" />
</Button>
Binding a Path:
<Button Content="{Binding Path}" /> <!-- Fill or stroke must be set in code unless set by the SVG converter -->
Binding a Geometry:
<Button>
<Path Width="100" Height="100" Data="{Binding Geometry}" />
</Button>
Install the SharpVectors library
Install-Package SharpVectors
Add the following in XAML
<UserControl xmlns:svgc="http://sharpvectors.codeplex.com/svgc">
<svgc:SvgViewbox Source="/Icons/icon.svg"/>
</UserControl>
Windows 10 build 15063 "Creators Update" natively supports SVG images (though with some gotchas) to UWP/UAP applications targeting Windows 10.
If your application is a WPF app rather than a UWP/UAP, you can still use this API (after jumping through quite a number of hoops): Windows 10 build 17763 "October 2018 Update" introduced the concept of XAML islands (as a "preview" technology but I believe allowed in the app store; in all cases, with Windows 10 build 18362 "May 2019 Update" XAML islands are no longer a preview feature and are fully supported) allowing you to use UWP APIs and controls in your WPF applications.
You need to first add the references to the WinRT APIs, and to use certain Windows 10 APIs that interact with user data or the system (e.g. loading images from disk in a Windows 10 UWP webview or using the toast notification API to show toasts), you also need to associate your WPF application with a package identity, as shown here (immensely easier in Visual Studio 2019). This shouldn't be necessary to use the Windows.UI.Xaml.Media.Imaging.SvgImageSource class, though.
Usage (if you're on UWP or you've followed the directions above and added XAML island support under WPF) is as simple as setting the Source for an <Image /> to the path to the SVG. That is equivalent to using SvgImageSource, as follows:
<Image>
<Image.Source>
<SvgImageSource UriSource="Assets/svg/icon.svg" />
</Image.Source>
</Image>
However, SVG images loaded in this way (via XAML) may load jagged/aliased. One workaround is to specify a RasterizePixelHeight or RasterizePixelWidth value that is double+ your actual height/width:
<SvgImageSource RasterizePixelHeight="300" RasterizePixelWidth="300" UriSource="Assets/svg/icon.svg" /> <!-- presuming actual height or width is under 150 -->
This can be worked around dynamically by creating a new SvgImageSource in the ImageOpened event for the base image:
var svgSource = new SvgImageSource(new Uri("ms-appx://" + Icon));
PrayerIcon.ImageOpened += (s, e) =>
{
var newSource = new SvgImageSource(svgSource.UriSource);
newSource.RasterizePixelHeight = PrayerIcon.DesiredSize.Height * 2;
newSource.RasterizePixelWidth = PrayerIcon.DesiredSize.Width * 2;
PrayerIcon2.Source = newSource;
};
PrayerIcon.Source = svgSource;
The aliasing may be hard to see on non high-dpi screens, but here's an attempt to illustrate it.
This is the result of the code above: an Image that uses the initial SvgImageSource, and a second Image below it that uses the SvgImageSource created in the ImageOpened event:
This is a blown up view of the top image:
Whereas this is a blown-up view of the bottom (antialiased, correct) image:
(you'll need to open the images in a new tab and view at full size to appreciate the difference)
After various searches and attempts I managed to find the method without having to use external libraries.
First you will need to use Inkscape to open the SVG file to prepare, then follow the procedure according to the following list:
Open the SVG file with Inkscape;
Press Ctrl + A to select everything;
Go to Edit > Resize page to selection;
Press Ctrl + C;
Press Ctrl + S then close Inkscape;
Open the SVG file a file editor then go to <path>, you could view several paths. This is an example:
<path d="..." fill="..." id="path2"/>
<path d="..." fill="..." id="path4"/>
<path d="..." fill="..." id="path6"/>
In your XAML file you have to create a ViewBox element, then insert a Grid element and then Path elements for the number of times when in the SVG file see the paths:
<Viewbox Stretch="Fill">
<Grid>
<Path Fill="..." Data="..."/>
<Path Fill="..." Data="..."/>
<Path Fill="..." Data="..."/>
</Grid>
</Viewbox>
Where in Fill property on your XAML you have to insert the fill property in the SVG file and in Data property on your XAML you have to insert the d property in the SVG file.
You should get a result like this:
Option 1: Use SVG icons directly using "SharpVectors" nuget package
Add SharpVectors nuget package to your project.
Add SVG files to your project, for example, in a "Icons" subfolder and set their Build Action property to Resource
Use it in your code:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
xmlns:local="clr-namespace:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<StackPanel>
<Button Height="100">
<svgc:SvgViewbox Source="/Icons/Checkmark_16x.svg"/>
</Button>
<ContentControl Height="100">
<svgc:SvgViewbox Source="/Icons/CollapseAll_16x.svg"/>
</ContentControl>
<Label Height="100">
<svgc:SvgViewbox Source="/Icons/Refresh_16x.svg"/>
</Label>
</StackPanel>
</Grid>
</Window>
Option 2: Convert SVG to XAML using "SvgToXaml" tool
SvgToXaml. Download the latest release (this answer was tested with the "Ver_1.3.0")
Place all your SVG icons into a folder and execute the following command:
SvgToXaml.exe BuildDict /inputdir "c:\Icons" /outputdir "c:\MyWpfApp" /outputname IconsDictionary
Add generated IconsDictionary.xaml file to your project and use it in your code:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApp"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="IconsDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<StackPanel>
<Button Height="100">
<Image Source="{StaticResource Refresh_16xDrawingImage}"/>
</Button>
<ContentControl Height="100">
<Image Source="{StaticResource CollapseAll_16xDrawingImage}"/>
</ContentControl>
<Label Height="100">
<Image Source="{StaticResource Checkmark_16xDrawingImage}"/>
</Label>
</StackPanel>
</Grid>
</Window>
Option 3: Use IValueConverter for some already generated XAML files
If you already have generated XAML files and you want to use them, for some types of them it is possible to create a custom ValueConverter class. Please refer to the following answers for more information:
Option 2: Use .xaml icon files directly
https://stackoverflow.com/a/21588195/7585517
You can use the resulting xaml from the SVG as a drawing brush on a rectangle. Something like this:
<Rectangle>
<Rectangle.Fill>
--- insert the converted xaml's geometry here ---
</Rectangle.Fill>
</Rectangle>
Use the SvgImage or the SvgImageConverter extensions, the SvgImageConverter supports binding.
See the following link for samples demonstrating both extensions.
https://github.com/ElinamLLC/SharpVectors/tree/master/TutorialSamples/ControlSamplesWpf
We can use directly the path's code from the SVG's code:
<Path>
<Path.Data>
<PathGeometry Figures="M52.8,105l-1.9,4.1c ...
Another alternative is dotnetprojects SVGImage
This allows native use of .svg files directly in xaml.
The nice part is, it is only one assembly which is about 100k. In comparision to sharpvectors which is much bigger any many files.
Usage:
...
xmlns:svg1="clr-namespace:SVGImage.SVG;assembly=DotNetProjects.SVGImage"
...
<svg1:SVGImage Name="mySVGImage" Source="/MyDemoApp;component/Resources/MyImage.svg"/>
...
That's all.
See:
https://www.nuget.org/packages/DotNetProjects.SVGImage/
https://github.com/dotnetprojects/SVGImage
I found this tutorial extremely helpful: https://msadowski.github.io/WPF-vector-graphics-tutorial/
Download the zip file for the program from github.
Use program to convert the SVG to XAML.
Copy/paste the .xaml file into your folder of choice in your project.
Add the application resource to App.xaml for your file.
Reference your vector image in your xaml page with Source="{StaticResource }"
The tutorial explains all steps very well with an example shown. I've tried it and my svg image is showing up great in my application now.
I am very new at this WPF world, i have some experience in the classic Windows Desktop applications.
I am trying to create a custom UserControl polygon shaped.
I have tryied creating a Path Data and then setting the UserControl Opacity property to "0", but it makes transparent the whole UserControl.
For example, i have build this Polygon inside the user control
<UserControl x:Class="WindowsFormsApp2.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="640" Height="480" Opacity="100">
<Grid x:Name="LayoutRoot">
<Path Data="M-70.616296,46.859802 L7.3270039,-1.2587545 174.31959,52.958763 168.71134,98.185567 z" Fill="#FF2121D6" HorizontalAlignment="Left" Height="100" Margin="138,114,0,0" Stretch="Fill" Stroke="Black" Opacity ="100" VerticalAlignment="Top" Width="246"/>
</Grid>
As you can see the user control is 640x480 so when i add code to the UserControl_MouseLeftButtonDown event, it fires if clicking in ay position inside the 640x480 while i want only to fire when clicking inside the polygon.
I have been googling for a solution but i can't found any solution, ¿maybe what i want it's not possible?
You may template a UserControl to look like a polygon:
<UserControl x:Class="WpfApp1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<UserControl.Template>
<ControlTemplate TargetType="UserControl">
<Path Data="M-70.616296,46.859802 L7.3270039,-1.2587545 174.31959,52.958763 168.71134,98.185567 z"
Fill="#FF2121D6" HorizontalAlignment="Left" Height="100" Margin="138,114,0,0"
Stretch="Fill" Stroke="Black" Opacity ="100" VerticalAlignment="Top" Width="246"/>
</ControlTemplate>
</UserControl.Template>
</UserControl>
Or you may just get rid of the UserControl and use the Path element directly. It also has a MouseLeftButtonDown event that you can handle.
In .Net 4.6, I use shared vector icons implemented as Path in Canvas in a global xaml like this:
<ResourceDictionary ...>
<Canvas x:Key="mSearchCanvas" x:Shared="False" Width="24" Height="24">
<Path Data="M9.5,3A6.5,6.5 0 0,1 16,9.5..." Fill="Black" />
</Canvas>
</ResourceDictionary
I can then reuse these icons in several applications using:
<Viewbox Width="16" Height="16" Child="{StaticResource mPencilCanvas}"/>
It works well but I'd like to use the same icon/Canvas with different Fill brushes.
Is there a simple way to override Fill property with new value?
I want to do something similar to Microsoft Powerpoint: I want to capture the current screen (or one grid from the current window), and then to set it as the content of the button (like powerpoint where there is a preview of the slides at the side bar).
What is the best way to do that? My current idea is to save it to PNG and then reload it as an image at the content of the button, but I'm sure there is a better way.
Thank you!
Try this:
<Grid>
<Viewbox
x:Name="Viewer"
Stretch="Uniform"
DataContext="{Binding ElementName=Thumbnail1, Path=Data}">
<Grid Width="224" Height="168" SnapsToDevicePixels="True" Margin="4,0,4,0">
<Grid.Background>
<VisualBrush Stretch="Uniform" TileMode="None" Visual="{Binding}" AlignmentY="Center"/>
</Grid.Background>
</Grid>
</Viewbox>
</Grid>
I was using saving as PNG approach in the beginning. Then I have found out the way as above. DataContext of the ViewBox is a canvas. I could create live previews of my screens this way however my screens were canvas objects.
I have a Canvas in a ResourceDictionary xaml file like so:
<Canvas x:Key="Icon">
<Path ... />
<Path ... />
</Canvas>
In my code-behind I load this icon using
LayoutGrid.Children.Add(FindResource("Icon") as Canvas);
And this works fine. Now I want to create a button that uses the same icon as a template. So I create a control template:
<ControlTemplate x:Key="IconTemplate">
...
</ControlTemplate>
Now here's the problem: How would I put the "Icon" resource canvas into the control template? As far as I know, Canvas does not have a Style or Template property. It has a Children property, but it's not accessible via XAML. How would I go about using my canvas in a template?
When you create a type such as canvas as a resource, then you are creating ONE instance of the type. This means that you cannot place that resource in more than one location in your application (an element can only be in one place at a time). You should look at using control templates, I think.
You don't need any code behind for this.
Something like this:
<ControlTemplate x:Key="Icon">
<Canvas>
<Path ... />
<Path ... />
</Canvas>
</ControlTemplate>
Then elsewhere you do something like this:
<Button>
<Control Template="{StaticResource Icon}" />
</Button>
This constructs a regular looking button with your icon as it's content. The content of that button is your icon.
If, however, you want to completely redefine the template of your button, then you would do so
<ControlTemplate x:Key="Icon" TargetType="Button">
<Canvas>
<Path ... />
<Path ... />
</Canvas>
</ControlTemplate>
Then elsewhere you do something like this:
<Button Template="{StaticResource Icon}" />
Note that this isn't a great style for a button. Look at this example from Microsoft for an example of a more fully featured button template.
EDIT
Unless you have a ContentPresenter in your ControlTemplate, then there's no need to assign the template to a content control. Note that any class derived from Control can be templated, including Control itself. So in order to place an item into your view, then you can just use:
<Control Template="{StaticResource Icon}" />
This uses the widest applicable type in the hierarchy, which is also the lightest.
A good way to do define an icon for a button is to use a DrawingBrush and set it as the fill of a Rectangle that you embed in the Button:
<Button>
<Rectangle
Width="32"
Height="32"
Fill={Background myDrawingBrush}
/>
</Button>
myDrawingBrush must be defined in resources like this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:PresentationOptions="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options">
<DrawingBrush x:Key="dialogerror" Stretch="Uniform">
<DrawingBrush.Drawing>
<DrawingGroup>
<GeometryDrawing>
... define geometry here ...
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</ResourceDictionary>