WPF ValueConverter与用于DrawingImage绑定的MarkupExtension

时间:2016-11-30 14:00:30

标签: c# wpf xaml valueconverter markup-extensions

我有一组存储在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>

所以现在有几个问题:

  1. 从性能角度来看,有什么更好的方法?这是一个简化的示例,在现实生活中,将有比Fill更多的属性。此外,在一个窗口上,很容易就会有几百个这样的图标。但是,图标本身在运行时不会改变(包括填充和颜色),那么最小化新对象创建的最佳做法是什么,并尽可能重用现有的DrawingImages?
  2. 是否应该注意其他任何差异?我更喜欢标记扩展语法,因为它看起来更干净。
  3. ValueConverter上的VS中发现了奇怪的Fill属性错误怎么办?由于这个原因,它不会编译,但奇怪的是它在设计师中完全没有渲染正确的画笔(Fill)。
  4. 我知道可以将Value Converters转换为静态的应用程序范围的资源,而不是Markup Extensions。那么,那么我将使用ValueConverter作为静态资源使事情更快,而不是标记扩展(我不能变成资源)?
  5. 何时使用ValueConverter vs MarkupExtension进行此类绑定的任何其他考虑因素(即涉及转换/转换逻辑的位置)?

0 个答案:

没有答案