XAML / WPF设计器无法解析将StaticResource作为参数的自定义MarkupExtension

时间:2018-02-06 23:29:47

标签: wpf visual-studio

当我使用StaticResource作为参数时,我遇到了自己创建的自定义资源扩展的问题。 根据{{​​3}},这应该有效: “支持嵌套多个标记扩展,并且每个标记扩展将首先进行最深入的评估。” 事实上它确实在运行时工作。但在设计时我发现内部StaticResource扩展没有解决 - 而是将StaticResource扩展本身传递给自定义的MarkupExtension,它不起作用。

我已经减少到绝对最小值来证明问题:

1)创建新的WPF应用程序“TestApp”

2)创建新类TestExtension,它只是从ProvideValue()返回其参数:

using System;
using System.Windows.Markup;

namespace TestApp
{
    public class TestExtension : MarkupExtension
    {
        public TestExtension(object param) { _originalValue = param; }
        public override object ProvideValue(IServiceProvider serviceProvider) { return _originalValue; }
        private object _originalValue;
    }
}

3)将资源添加到主窗口并将其用作扩展名的参数:

<Window x:Class="TestApp.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:TestApp"
        xmlns:sys="clr-namespace:System;assembly=mscorlib" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <ResourceDictionary>
            <sys:Double x:Key="TestResource">99</sys:Double>
        </ResourceDictionary>
    </Window.Resources>

    <Grid Background="Red" Width="{local:TestExtension {StaticResource TestResource}}" Height="99" />

</Window>

构建并运行并且它工作正常 - 但在设计器中,Grid的宽度是“Auto”而不是99,并且在编辑器中Width属性被误解为错误'System.Windows.StaticResourceExtension'不是属性'宽度'的有效值。

你可能认为你可以检测到这种情况并在传入的StaticResourceExtension中调用ProvideValue(),如下所示:

using System;
using System.Windows;
using System.Windows.Markup;

namespace WPFGUI.MarkupExtensions
{
    public class TestExtension : MarkupExtension
    {
        public TestExtension(object param)
        {
            _originalValue = param;
        }

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            if (_originalValue.GetType() == typeof(StaticResourceExtension))
            {
                _originalValue = (_originalValue as StaticResourceExtension).ProvideValue(serviceProvider);
                throw new XamlParseException("This exception will not hit because the above line does not execute at design time.");
            }

            return _originalValue;
        }

        private object _originalValue;
    }
}

......但这也不起作用。设计器在遇到对StaticResourceException的调用时停止运行TestExtension:ProvideValue():ProvideValue()。

1 个答案:

答案 0 :(得分:0)

为了记录,我找到了一种方法:

public class TestExtension : MarkupExtension
{
    public TestExtension(object param)
    {
        _param = param;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (_param is StaticResourceExtension || _param is DynamicResourceExtension)
        {
            IProvideValueTarget pvt = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
            object key = (_param as StaticResourceExtension)?.ResourceKey ?? (_param as DynamicResourceExtension)?.ResourceKey;
            return (pvt.TargetObject as FrameworkElement)?.FindResource(key) ?? (pvt.TargetObject as FrameworkContentElement)?.FindResource(key);
        }
        return _param;
    }

    private object _param;
}