【问题标题】:Vector image as reusable XAML fragment作为可重用 XAML 片段的矢量图像
【发布时间】:2010-12-08 12:20:34
【问题描述】:

我想在一些 WPF 应用程序/库中重用一些 XAML 片段作为图像。

问题的背景如下:

在 WPF 应用程序中重用位图图像很容易。图片可以作为资源添加,我可以在 XAML 的很多地方使用<Image Source="packURI"/>,所以图片是一样的。

但我希望有可能对矢量图像执行相同的操作。图像本身可以表示为Path,但我不能重复使用相同的Path 作为资源,因为禁止在多个不同的地方(可能来自多个 UI 线程)简单地使用它(UI 元素只能有一个逻辑父母)。

此外,如果我想从多个Paths 构建“图像”,问题会变得更加复杂,请使用Canvas。或者一些任意的 XAML 代码。

我尝试将Style 用于Path,因此图像以这种方式表示:

<Path Style={StaticResource VectorImage1}/>

这似乎是一种可重用的方式,但我担心两个问题:

  1. 如果矢量图像的实现从Path 更改为(例如)Canvas,我不仅需要在样式中替换它,而且在使用它的源代码中的任何地方都需要替换它。
  2. 使用样式定义路径似乎过于冗长。
  3. 我认为没有办法概括这种使用Canvas 或任意XAML 代码的方法。
  4. 语法似乎很不自然。

还有其他方法可以通过定义UserControl 来获得可重用的 XAML 片段,但为每个矢量图像定义单独的用户控件似乎有点过头了。

是否有更好、更好、正确的方法来定义可重用的 XAML 片段?

【问题讨论】:

    标签: c# wpf xaml resources


    【解决方案1】:

    您可以将 x:Shared 属性添加到路径资源并将其用作静态资源。如果“MyVectorImage”更改为其他内容,这将起作用

    更新
    可能最好使用 ContentControl 或类似的能够添加属性,例如 Margin 等。

    <Window.Resources>
        <Path x:Key="MyVectorImage"
              x:Shared="False"
              Stroke="DarkGoldenRod"
              StrokeThickness="3"
              Data="M 10,20 C 10,25 40,35 40,17 H 28"
              Stretch="Fill"
              Width="100"
              Height="40"/>
    </Window.Resources>
    <StackPanel>
        <ContentControl Margin="10" Content="{StaticResource MyVectorImage}"/>
        <ContentControl Margin="10" Content="{StaticResource MyVectorImage}"/>
    </StackPanel>
    

    示例。您将“MyVectorImage”替换为包含两个路径的 StackPanel。

    <Window.Resources>
        <StackPanel x:Key="MyVectorImage"
                    x:Shared="False">
            <Path Stroke="DarkGoldenRod"
                  StrokeThickness="3"
                  Data="M 10,20 C 10,25 40,35 40,17 H 28"
                  Stretch="Fill"
                  Width="100"
                  Height="40"/>
            <Path Stroke="DarkGoldenRod"
                  StrokeThickness="3"
                  Data="M 10,20 C 10,25 40,35 40,17 H 28"
                  Stretch="Fill"
                  Width="100"
                  Height="40"/>
        </StackPanel>
    </Window.Resources>
    

    【讨论】:

    • 我尝试使用您的建议,但在运行时出现异常:“命名空间中的共享属性 'http://schemas.microsoft.com/winfx/2006/xaml' 只能用于编译的资源字典。”我将 MyVectorImage 移动到单独的 XAML 资源字典中,但是当我将该字典包含到 Window 的 MergedDictionaries 中时,我收到了相同的错误消息。
    • @Vlad@ 我更新了我的示例。如果您尝试使用 StackPanel 的示例,我忘记将 x:Shared 属性移动到 StackPanel。
    • 我明白了,我的错,我应该试着理解阅读消息的确切内容。 x:Shared 仅在顶层有效。
    • @Vlad:是的,当我尝试运行它时,我遇到了同样的异常。它在设计器中显示得很好,所以我没有费心去实际尝试运行它:)
    • 酷对我有用。现在我可以将所有矢量图形保存在单独的资源字典中!
    【解决方案2】:

    经过一番研究,还有一个选择:将DrawingImage 用作图像的Source。通常的图像源是BitmapSource,但也可以是“矢量图形”。

    这里是an example

    <Image>
      <Image.Source>
        <DrawingImage PresentationOptions:Freeze="True">
          <DrawingImage.Drawing>
            <GeometryDrawing>
              <GeometryDrawing.Geometry>
                <GeometryGroup>
                  <EllipseGeometry Center="50,50" RadiusX="45" RadiusY="20" />
                  <EllipseGeometry Center="50,50" RadiusX="20" RadiusY="45" />
                </GeometryGroup>
              </GeometryDrawing.Geometry>
              <GeometryDrawing.Brush>
                <LinearGradientBrush>
                  <GradientStop Offset="0.0" Color="Blue" />
                  <GradientStop Offset="1.0" Color="#CCCCFF" />
                </LinearGradientBrush>
              </GeometryDrawing.Brush>
              <GeometryDrawing.Pen>
                <Pen Thickness="10" Brush="Black" />
              </GeometryDrawing.Pen>
            </GeometryDrawing>
          </DrawingImage.Drawing>
        </DrawingImage>
      </Image.Source>
    </Image>
    

    生成如此漂亮的矢量图像:

    另一个选项可能是使用DrawingBrush,例如在这个 SO 问题中:How to store and retrieve multiple shapes in XAML/WPF?

    【讨论】:

    • 我更喜欢这种方法,但我认为答案将受益于一些内联代码示例。使用 DrawingImage 允许您通过将 元素用作 DrawingImage 的内容属性,将多个矢量图形(和多种颜色)组合成一个单一的、有凝聚力的图标。它还允许您 - 在您的 UI 代码中 - 始终为您的图标使用 元素,无论您指的是矢量图像还是位图图像; “Source”属性将引用 DrawingImage 矢量资源或 BitmapSource 图像资源。
    • @BTownTKD:你说得对,我会尝试构建一些例子
    • 示例链接已损坏,无法恢复。 (该成员的 MSDN 内容没有示例。)有人在此站点上分享内容吗?
    • @LonelyPixel:我已经更正了链接并内联了示例。
    【解决方案3】:

    您可以将路径存储在资源字典中并将 x:Shared 设置为 false:

    <Path x:Key="CrossPath"
          x:Shared="false"
          ...
          />
    

    这将告诉 WPF 在每次请求时创建一个新实例。 http://msdn.microsoft.com/en-us/library/aa970778.aspx

    【讨论】:

    • 这适用于任意 WPF 片段吗?例如,Canvas 带有子元素?
    • 非常感谢;您的建议与接受的答案基本相同。
    • 感谢您解释 shared=false 的实际作用,它解决了我的问题
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多