我有一组存储在ResourceDictionary中的图标作为Geometry
个对象。我的目的是使用它们为按钮等UI元素创建图标。我需要能够以各种方式自定义这些图标:
可以显示此类图标的大多数UI元素都期望ImageSource
作为目标类型。因此,我需要一个性能良好且易于使用的机制,将我的Geometry
资源转换为实际的ImageSource
。在伪代码中:
ImageSource Convert(Geometry resource, RenderOptions options)
其中options
表示我可能需要的各种自定义设置,如画笔,颜色等。
我的理解是有两种通用方法:标记扩展和值转换器。我创建了两个派生类,它们来自一个共同的基础。基类实际上定义了转换逻辑,而2个助手提供了特定于MarkupExtension和ValueConverter的功能:
namespace MyWPFHelpers {
/// <summary>
/// Provides functionality for actual conversion. Also defines various options. In this example just Fill.
/// </summary>
public abstract class GeometryImageBase : MarkupExtension
{
public Brush Fill { get; set; } = Brushes.Black;
public DrawingImage CreateImage(Geometry g)
{
var d = new GeometryDrawing(Fill, null, g).FreezeAndReturn();
var di = new DrawingImage(d).FreezeAndReturn();
return di;
}
}
[MarkupExtensionReturnType(typeof(DrawingImage))]
public class GeometryImageExetnsion : GeometryImageBase
{
public Geometry Value { get; set; }
public override object ProvideValue(IServiceProvider serviceProvider)
{
return CreateImage(Value);
}
}
[ValueConversion(typeof(Geometry), typeof(DrawingImage))]
public class GeometryImageConverter : GeometryImageBase, IValueConverter
{
/// <summary>
/// Unfortunately we need to provide this since we inherit from GeometryImageBase that provides conversion functionality (which itself inherits from MarkupExtension)
/// </summary>
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return CreateImage((Geometry)value);
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
return null;
}
}
}
FreezeAndReturn()
只是一个简单的辅助方法,用于冻结对象并在冻结后返回它。
现在,在XAML标记中,我可以按如下方式使用这些类:
<Window x:Class="MyProject.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:o="http://schemas.microsoft.com/winfx/2006/xaml/presentation/options"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfx="clr-namespace:MyWPFHelpers"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Geometry x:Key="myicongeometry" o:Freeze="True">M16,56L16,26 32,8 48,26 48,56 16,56z</Geometry>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" x:Key="mybrush" o:Freeze="True">
<GradientStop Color="Black" Offset="0"/>
<GradientStop Color="Red" Offset="1"/>
</LinearGradientBrush>
</Window.Resources>
<Grid>
<!-- Using Value Converter -->
<Image Height="94" Width="95" Margin="207,98,215,127"
Source="{Binding Source={StaticResource myicongeometry},
Converter={wpfx:GeometryImageConverter Fill={StaticResource mybrush}}}" />
<!--
Incidentally, for some reason the above line "Fill={StaticResource mybrush}"
produces this error in VS 2015 and VS 2017:
"Unknown property 'Fill' for type 'MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension' encountered while parsing a Markup Extension."
However, if I change that line to say: "Fill=Red"
everything works fine. However in both cases,
the content is rendered correctly.
Anyone knows why?
-->
<!-- Using Markup Extension -->
<Image Source="{wpfx:GeometryImageExetnsion
Fill={StaticResource mybrush},
Value={StaticResource myicongeometry}}"
Margin="352,107,70,118"/>
</Grid>
</Window>
所以现在有几个问题:
Fill
更多的属性。此外,在一个窗口上,很容易就会有几百个这样的图标。但是,图标本身在运行时不会改变(包括填充和颜色),那么最小化新对象创建的最佳做法是什么,并尽可能重用现有的DrawingImages?Fill
属性错误怎么办?由于这个原因,它不会编译,但奇怪的是它在设计师中完全没有渲染正确的画笔(Fill)。