WPF 在WPF中使用SVG文件作为图标的正确方法是啥

Posted

技术标签:

【中文标题】WPF 在WPF中使用SVG文件作为图标的正确方法是啥【英文标题】:WPF What is the correct way of using SVG files as icons in WPFWPF 在WPF中使用SVG文件作为图标的正确方法是什么 【发布时间】:2011-04-01 09:07:54 【问题描述】:

有人可以描述一个推荐的分步过程吗?

步骤 1。将 SVG 转换为 XAML……很简单

步骤 2。现在呢?

【问题讨论】:

很抱歉复活这篇文章,但我认为这些信息很有价值:SVG 本质上是与 WPF 路径的一对一匹配。因此,除了一些表面的标记调整之外,您应该能够将 SVG 直接带入您的 WPF 应用程序。最多您可能必须将路径托管到画布中,但仅此而已,恕我直言。 【参考方案1】:

您的技术将取决于您的 SVG 到 XAML 转换器生成的 XAML 对象。它会产生图纸吗?一个图像?网格?帆布?一条路径?几何?在每种情况下,您的技术都会有所不同。

在下面的示例中,我将假设您在按钮上使用图标,这是最常见的情况,但请注意,相同的技术适用于任何 ContentControl。

使用绘图作为图标

要使用绘图,请使用 DrawingBrush 绘制适当大小的矩形:

<Button>
  <Rectangle Width="100" Height="100">
    <Rectangle.Fill>
      <DrawingBrush>
        <DrawingBrush.Drawing>

          <Drawing ... /> <!-- Converted from SVG -->

        </DrawingBrush.Drawing>
      </DrawingBrush>
    </Rectangle.Fill>
  </Rectangle>
</Button>

使用图像作为图标

可以直接使用图片:

<Button>
  <Image ... />  <!-- Converted from SVG -->
</Button>

使用网格作为图标

可以直接使用网格:

<Button>
  <Grid ... />  <!-- Converted from SVG -->
</Button>

如果您需要控制大小,也可以将其包含在 Viewbox 中:

<Button>
  <Viewbox ...>
    <Grid ... />  <!-- Converted from SVG -->
  </Viewbox>
</Button>

使用画布作为图标

这类似于使用图像或网格,但由于画布没有固定大小,您需要指定高度和宽度(除非这些已由 SVG 转换器设置):

<Button>
  <Canvas Height="100" Width="100">  <!-- Converted from SVG, with additions -->
  </Canvas>
</Button>

使用路径作为图标

您可以使用路径,但必须明确设置笔触或填充:

<Button>
  <Path Stroke="Red" Data="..." /> <!-- Converted from SVG, with additions -->
</Button>

<Button>
  <Path Fill="Blue" Data="..." /> <!-- Converted from SVG, with additions -->
</Button>

使用几何图形作为图标

您可以使用路径来绘制几何图形。如果要描边,设置描边:

<Button>
  <Path Stroke="Red" Width="100" Height="100">
    <Path.Data>
      <Geometry ... /> <!-- Converted from SVG -->
    </Path.Data>
  </Path>
</Button>

或者如果应该填充,设置填充:

<Button>
  <Path Fill="Blue" Width="100" Height="100">
    <Path.Data>
      <Geometry ... /> <!-- Converted from SVG -->
    </Path.Data>
  </Path>
</Button>

如何绑定数据

如果您在代码中执行 SVG -> XAML 转换并希望使用数据绑定显示生成的 XAML,请使用以下方法之一:

绑定绘图:

<Button>
  <Rectangle Width="100" Height="100">
    <Rectangle.Fill>
      <DrawingBrush Drawing="Binding Drawing, Source=StaticResource ..." />
    </Rectangle.Fill>
  </Rectangle>
</Button>

绑定图片:

<Button Content="Binding Image" />

绑定网格:

<Button Content="Binding Grid" />

在 Viewbox 中绑定 Grid:

<Button>
  <Viewbox ...>
    <ContentPresenter Content="Binding Grid" />
  </Viewbox>
</Button>

绑定画布:

<Button>
  <ContentPresenter Height="100" Width="100" Content="Binding Canvas" />
</Button>

绑定路径:

<Button Content="Binding Path" />  <!-- Fill or stroke must be set in code unless set by the SVG converter -->

绑定几何体:

<Button>
  <Path Width="100" Height="100" Data="Binding Geometry" />
</Button>

【讨论】:

+10 只是花时间举例说明所有情况在我的情况下,我有一个画布,所以我假设以下适用 但是我如何重用它呢?我无法为要使用 svg 图像的每个按钮进行复制/粘贴。我有点想将其定义为字典中的资源并用作静态/动态资源。 您不能在 UI 的多个位置使用单个 Canvas,因为 Visual 只能有一个父级。因此,您通常会为此使用模板。模板允许您在每个需要的地方创建单独的 Canvas 实例:&lt;ResourceDictionary&gt;&lt;DataTemplate x:Key="MyIconTemplate"&gt;&lt;Canvas ... /&gt;&lt;/DataTemplate&gt;&lt;/ResourceDictionary&gt; ... &lt;Button&gt;&lt;ContentPresenter ContentTemplate="StaticResource MyIconTemplate" /&gt;&lt;/Button&gt; 一种更有效但更复杂的方法是使用 VisualBrush 创建要绘制的画布图片:&lt;ResourceDictionary&gt;&lt;VisualBrush x:Key="MyBrush"&gt;&lt;VisualBrush.Visual&gt;&lt;Canvas x:Key="MyCanvas" ... /&gt;&lt;/VisualBrush.Visual&gt;&lt;/VisualBrush&gt;&lt;/ResourceDictionary&gt; ... &lt;Button&gt;&lt;Rectangle Fill="StaticResource MyBrush" Width="..." Height="..." /&gt;&lt;/Button&gt;。这更难,因为您还必须确保 Canvas 得到测量/排列,并且您必须对宽度/高度进行硬编码(或使用矩形模板)。 啊哈!!!我知道我不能直接使用同一画布两次,这就是为什么尚未接受答案的原因。非常感谢。 所以基本上,对于这些元素中的每一个 - 例如Canvas 对象,我将 SVG 放在哪里?这很重要,因为我的 SVG 都在静态资源中,我需要嵌入它们...【参考方案2】:

安装SharpVectors 库

Install-Package SharpVectors

在 XAML 中添加以下内容

<UserControl xmlns:svgc="http://sharpvectors.codeplex.com/svgc">
    <svgc:SvgViewbox Source="/Icons/icon.svg"/>
</UserControl>

【讨论】:

将 XAML 图像嵌入应用程序还是使用这种方法更好? 对我来说效果很好...... 用 nugets 等等。我必须正确制作带有颜色信息的 svg,但是一旦解决了,它们就不会显示为黑色,而是看起来不错。 以下是如何使用Sharpvectors 绑定到Source AttachedProperty:***.com/a/35088090/828184 2020 年更新有一个新版本使用 SharpVectors.Reloaded 2020 年 11 月:1.7.0 为 SvgViewbox 的 Source 属性抛出 NullReference 异常,无论内容如何。降级到 1.6.0 (SharpVectors.Reloaded),它可以在那里工作。【参考方案3】:

Windows 10 build 15063“Creators Update”本机支持面向 Windows 10 的 UWP/UAP 应用程序的 SVG 图像(尽管存在一些问题)。

如果您的应用程序是 WPF 应用程序而不是 UWP/UAP,您仍然可以使用此 API(在经历了相当多的麻烦之后):Windows 10 build 17763 “October 2018 Update”引入了XAML 岛(作为“预览”技术,但我相信在应用商店中允许使用;在所有情况下,Windows 10 build 18362“2019 年 5 月更新”XAML 岛不再是预览功能并且完全受支持)允许您使用 UWP WPF 应用程序中的 API 和控件。

您需要首先add the references to the WinRT APIs,并使用某些与用户数据或系统交互的 Windows 10 API(例如,在 Windows 10 UWP webview 中从磁盘加载图像或使用 toast 通知 API 来显示 toast ),您还需要将您的 WPF 应用程序与包标识 as shown here 相关联(在 Visual Studio 2019 中非常容易)。不过,这对于使用 Windows.UI.Xaml.Media.Imaging.SvgImageSource 类不是必需的。

使用(如果您使用 UWP 或者您已按照上述说明并在 WPF 下添加了 XAML 岛支持)就像将 Source&lt;Image /&gt; 设置为 SVG 的路径一样简单。那相当于使用SvgImageSource,如下:

<Image>
    <Image.Source>
        <SvgImageSource UriSource="Assets/svg/icon.svg" />
    </Image.Source>
</Image>

但是,SVG 图像以这种方式加载(通过 XAML)may load jagged/aliased。一种解决方法是指定一个 RasterizePixelHeightRasterizePixelWidth 值,它是你的实际高度/宽度的两倍:

<SvgImageSource RasterizePixelHeight="300" RasterizePixelWidth="300" UriSource="Assets/svg/icon.svg" /> <!-- presuming actual height or width is under 150 -->

这可以通过在基本图像的ImageOpened 事件中创建一个新的SvgImageSource 来动态解决:

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;

在非高 dpi 屏幕上可能很难看到锯齿,但这里尝试说明一下。

这是上面代码的结果:一个Image 使用初始SvgImageSource,第二个Image 使用在ImageOpened 事件中创建的SvgImageSource:

这是上图的放大图:

而这是底部(抗锯齿,正确)图像的放大视图:

(您需要在新标签页中打开图像并以全尺寸查看以了解差异)

【讨论】:

SvgImageSource 是一个 UWP 库,而不是 WPF,很遗憾。 这是 UWP 而不是 WPF;你在混淆 XAML【参考方案4】:

您可以将 SVG 生成的 xaml 用作矩形上的绘图笔刷。像这样的:

<Rectangle>
   <Rectangle.Fill>
      --- insert the converted xaml's geometry here ---
   </Rectangle.Fill>
</Rectangle>

【讨论】:

与第一个答案相同的问题。我不想每次我想使用相同的 svg 时都复制粘贴。 也没有谈论转换以及它是如何完成的。【参考方案5】:

使用 SvgImage 或 SvgImageConverter 扩展,SvgImageConverter 支持绑定。 有关演示这两种扩展的示例,请参阅以下链接。

https://github.com/ElinamLLC/SharpVectors/tree/master/TutorialSamples/ControlSamplesWpf

【讨论】:

【参考方案6】:

经过各种搜索和尝试,我设法找到了该方法,而无需使用外部库。 首先您需要使用Inkscape打开SVG文件进行准备,然后按照以下列表进行操作:

用 Inkscape 打开 SVG 文件; 按 Ctrl + A 选择所有内容; 转到编辑 > 调整页面大小以选择; 按 Ctrl + C; 按 Ctrl + S 然后关闭 Inkscape; 在文件编辑器中打开 SVG 文件,然后转到 &lt;path&gt;,您可以查看多个路径。这是一个例子:
<path d="..." fill="..." id="path2"/>
<path d="..." fill="..." id="path4"/>
<path d="..." fill="..." id="path6"/>
在您的 XAML 文件中,您必须创建一个 ViewBox 元素,然后插入一个 Grid 元素和 Path 元素,以便在 SVG 文件中看到路径的次数:
<Viewbox Stretch="Fill">
    <Grid>
        <Path Fill="..." Data="..."/>
        <Path Fill="..." Data="..."/>
        <Path Fill="..." Data="..."/>
    </Grid>
</Viewbox>

在 XAML 的 Fill 属性中,您必须在 SVG 文件中插入 fill 属性,在 XAML 的 Data 属性中,您必须在 SVG 文件中插入 d 属性。

你应该得到这样的结果:

【讨论】:

【参考方案7】:

我们可以直接使用SVG代码中的路径代码:

    <Path>
        <Path.Data>
            <PathGeometry Figures="M52.8,105l-1.9,4.1c ... 

【讨论】:

【参考方案8】:

另一种选择是 dotnetprojects SVGImage

这允许直接在 xaml 中本地使用 .svg 文件。

好的部分是,它只有一个组件,大约 100k。与任何许多文件都大得多的sharpvectors相比。

用法:

...
xmlns:svg1="clr-namespace:SVGImage.SVG;assembly=DotNetProjects.SVGImage"
...
<svg1:SVGImage Name="mySVGImage" Source="/MyDemoApp;component/Resources/MyImage.svg"/>
...

就是这样。

见:

https://www.nuget.org/packages/DotNetProjects.SVGImage/ https://github.com/dotnetprojects/SVGImage

【讨论】:

我想使用这个解决方案,但它显示“无法定位资源”,即使将 SVG 图标的构建操作设置为 Resource。【参考方案9】:

选项 1:使用“SharpVectors”nuget 包直接使用 SVG 图标

    将SharpVectors nuget 包添加到您的项目中。 将 SVG 文件添加到您的项目中,例如,在“图标”子文件夹中,并将其 Build Action 属性设置为 Resource 在您的代码中使用它:
<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>

选项 2:使用“SvgToXaml”工具将 SVG 转换为 XAML

    SvgToXaml。下载latest release(此答案已使用“Ver_1.3.0”进行测试) 将所有 SVG 图标放入一个文件夹并执行以下命令:
SvgToXaml.exe BuildDict /inputdir "c:\Icons" /outputdir "c:\MyWpfApp" /outputname IconsDictionary
    将生成的IconsDictionary.xaml 文件添加到您的项目中并在您的代码中使用:
<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>

选项 3:对一些已生成的 XAML 文件使用 IValueConverter

如果您已经生成了 XAML 文件并且想要使用它们,则可以为其中的某些类型创建自定义 ValueConverter 类。更多信息请参考以下答案:

Option 2: Use .xaml icon files directly https://***.com/a/21588195/7585517

【讨论】:

以上是关于WPF 在WPF中使用SVG文件作为图标的正确方法是啥的主要内容,如果未能解决你的问题,请参考以下文章

存储 WPF 图像资源

在WPF中使用FontAwesome之类的字体图标

Font Awesome矢量版,十六进制版,WPF字体使用

WPF 让窗口激活作为前台最上层窗口的方法

WPF 让窗口激活作为前台最上层窗口的方法

更改WPF窗口图标