本文介绍了标记扩展'StaticResourceExtension'需要'IXamlSchemaContextProvider'在的IServiceProvider的ProvideValue实施的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

一个资源扩展我已经使用了几年,现在停在一个新的.NET 4中的项目,下面的错误在设计时的工作:

从扩展的相关方法如下:

 公众覆盖对象ProvideValue(的IServiceProvider的ServiceProvider)
    {
        风格resultStyle =新样式();
        的foreach(在resourceKeys串currentResourceKey)
        {
            对象键= currentResourceKey;
            如果(currentResourceKey ==)。
            {
                IProvideValueTarget服务=(IProvideValueTarget)serviceProvider.GetService(typeof运算(IProvideValueTarget));
                键= service.TargetObject.GetType();
            }
            风格currentStyle =新StaticResourceExtension(键).ProvideValue(的ServiceProvider)的风格;
            如果(currentStyle == NULL)
                抛出新的InvalidOperationException异常(无法找到风格,资源键+ currentResourceKey +。);
            resultStyle.Merge(currentStyle);
        }
        返回resultStyle;
    }
 

presumably,编译器给错误,因为当我打电话 currentStyle =新StaticResourceExtension(键).ProvideValue(的ServiceProvider); 的的ServiceProvider我并传递缺少IXamlSchemaContextProvider信息。不知道它会来的,虽然,我甚至不知道如何服务提供商的标记扩展在第一时间获取设置,我只是用这样的:

<风格X:关键=ReadOnlyTextCell的TargetType ={X:类型的TextBlock}支持算法FMP ={UTIL:MultiStyle ReadOnlyCell TextCell}/>


满code的扩展是在这里:

 使用系统;
使用System.Windows;
使用System.Windows.Markup;

/ * MultiStyleExtension  - 用于合并多个现有样式。
 *
 * 例:
    <窗​​口的xmlns:地方=CLR的命名空间:FlagstoneRe.WPF.Utilities.UI>
        < Window.Resources>
            <风格X:关键=按钮样式的TargetType =按钮>
                < setter属性=宽度值=120/>
                < setter属性=高度值=25/>
                < setter属性=字号的价值=12/>
            < /样式和GT;
            <风格X:关键=GreenButtonStyle的TargetType =按钮>
                < setter属性=前景VALUE =绿色/>
            < /样式和GT;
            <风格X:关键=RedButtonStyle的TargetType =按钮>
                < setter属性=前景VALUE =红/>
            < /样式和GT;
            <风格X:关键=BoldButtonStyle的TargetType =按钮>
                < setter属性=粗细VALUE =大胆/>
            < /样式和GT;
        < /Window.Resources>

        <按钮样式={地方:MultiStyle按钮样式GreenButtonStyle}CONTENT =绿色按钮/>
        <按钮样式={地方:MultiStyle按钮样式RedButtonStyle}CONTENT =红色按钮/>
        <按钮样式={地方:MultiStyle按钮样式GreenButtonStyle BoldButtonStyle}CONTENT =绿色,大胆键/>
        <按钮样式={地方:MultiStyle按钮样式RedButtonStyle BoldButtonStyle}CONTENT =红,加粗按钮/>

 *请注意语法就像使用多个CSS类。
 *一类的当前默认的样式可以通过合并。句法:

        <按钮样式={地方:MultiStyle GreenButtonStyle BoldButtonStyle}内容=粗体绿色键/>

 * /

命名空间FlagstoneRe.WPF.Utilities.UI
{
    [MarkupExtensionReturnType(typeof运算(风格))]
    公共类MultiStyleExtension:的MarkupExtension
    {
        私人字符串[] resourceKeys;

        ///<总结>
        ///公共构造函数。
        ///< /总结>
        ///< PARAM NAME =inputResourceKeys>的构造函数的输入应该包括用空格分隔的一个或多个样式名称字符串< /参数>
        公共MultiStyleExtension(字符串inputResourceKeys)
        {
            如果(inputResourceKeys == NULL)
                抛出新ArgumentNullException(inputResourceKeys);
            this.resourceKeys = inputResourceKeys.Split(新的char [] {''},StringSplitOptions.RemoveEmptyEntries);
            如果(this.resourceKeys.Length == 0)
                抛出新的ArgumentException(指定输入资源键。);
        }

        ///<总结>
        ///返回与合并在构造函数中指定的键的所有样式的样式。
        ///< /总结>
        ///< PARAM NAME =的ServiceProvider>服务提供商此标记扩展< /参数>
        ///<返回>的合并,在构造函数中指定的按键和LT各种风格样式; /回报>
        公众覆盖对象ProvideValue(的IServiceProvider的ServiceProvider)
        {
            风格resultStyle =新样式();
            的foreach(在resourceKeys串currentResourceKey)
            {
                对象键= currentResourceKey;
                如果(currentResourceKey ==)。
                {
                    IProvideValueTarget服务=(IProvideValueTarget)serviceProvider.GetService(typeof运算(IProvideValueTarget));
                    键= service.TargetObject.GetType();
                }
                风格currentStyle =新StaticResourceExtension(键).ProvideValue(的ServiceProvider)的风格;
                如果(currentStyle == NULL)
                    抛出新的InvalidOperationException异常(无法找到风格,资源键+ currentResourceKey +。);
                resultStyle.Merge(currentStyle);
            }
            返回resultStyle;
        }
    }

    公共静态类MultiStyleMethods
    {
        ///<总结>
        ///融合了两种风格作为参数传递。第一样式将被修改为包括任何
        ///信息present在第二位。如果有冲突,第二样式优先。
        ///< /总结>
        ///&所述; PARAM NAME =STYLE1>首先样式合并,这将被修改以包括从第二个信息&所述; /参数>
        ///< PARAM NAME =蓝紫魅力>第二个样式合并< /参数>
        公共静态无效的合并(这个风格样式1,样式蓝紫魅力)
        {
            如果(STYLE1 == NULL)
                抛出新ArgumentNullException(样式1);
            如果(蓝紫魅力== NULL)
                抛出新ArgumentNullException(蓝紫魅力);
            如果(style1.TargetType.IsAssignableFrom(style2.TargetType))
                style1.TargetType = style2.TargetType;
            如果(style2.BasedOn!= NULL)
                合并(STYLE1,style2.BasedOn);
            的foreach(SetterBase currentSetter在style2.Setters)
                style1.Setters.Add(currentSetter);
            的foreach(TriggerBase currentTrigger在style2.Triggers)
                style1.Triggers.Add(currentTrigger);
            //这个code使用DynamicResources时,才需要。
            的foreach(在style2.Resources.Keys对象键)
                style1.Resources [关键] = style2.Resources [关键];
        }
    }
}
 

解决方案

我遇到了同样的问题。一些额外的信息:

在运行时,IServiceProvider的值类型是MS.Internal.Xaml.ServiceProviderContext。

在Visual Studio的XAML设计,该IServiceProvider的值类型"Microsoft.Ex$p$pssion.DesignModel.Core.InstanceBuilderOperations.InstanceBuilderServiceProvider".

显然,VS2010采用的类防爆pression混合,以提供比VS2008有更好的设计时行为 - 但有代价的,因为防爆pression混合类不具有所有的相同信息实际运行时间系统。

更多信息:我想插入我自己的类同时实现的IServiceProvider和IXamlSchemaContextProvider。有些调用就会传递给原来的IServiceProvider,我提供了一个虚拟的(空)XamlSchemaContext时提出要求。但我仍然得到同样的错误。

里面的东西WPF是封装我的IServiceProvider与其他的IServiceProvider类型 - 即不执行IXamlSchemaContextProvider但之一。我对如何解决这个没有进一步的想法。

A resource extension I've been using for a few years now stopped working at design time in a new .Net 4 project with the following error:

The relevant method from the extension is the following:

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        Style resultStyle = new Style();
        foreach (string currentResourceKey in resourceKeys)
        {
            object key = currentResourceKey;
            if (currentResourceKey == ".")
            {
                IProvideValueTarget service = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
                key = service.TargetObject.GetType();
            }
            Style currentStyle = new StaticResourceExtension(key).ProvideValue(serviceProvider) as Style;
            if (currentStyle == null)
                throw new InvalidOperationException("Could not find style with resource key " + currentResourceKey + ".");
            resultStyle.Merge(currentStyle);
        }
        return resultStyle;
    }

Presumably, the compiler is giving the error because when I call currentStyle = new StaticResourceExtension(key).ProvideValue(serviceProvider);, the serviceProvider I'm passing along is missing IXamlSchemaContextProvider information. Don't know where it would come from though, I don't even know how the service provider for the markup extension gets set in the first place, I just use it like this:

<Style x:Key="ReadOnlyTextCell" TargetType="{x:Type TextBlock}" BasedOn="{util:MultiStyle ReadOnlyCell TextCell}"/>


The full code for the extension is here:

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

/* MultiStyleExtension - used to merge multiple existing styles.
 *  
 * Example:
    <Window xmlns:local="clr-namespace:FlagstoneRe.WPF.Utilities.UI">
        <Window.Resources>
            <Style x:Key="ButtonStyle" TargetType="Button">
                <Setter Property="Width" Value="120" />
                <Setter Property="Height" Value="25" />
                <Setter Property="FontSize" Value="12" />
            </Style>
            <Style x:Key="GreenButtonStyle" TargetType="Button">
                <Setter Property="Foreground" Value="Green" />
            </Style>
            <Style x:Key="RedButtonStyle" TargetType="Button">
                <Setter Property="Foreground" Value="Red" />
            </Style>
            <Style x:Key="BoldButtonStyle" TargetType="Button">
                <Setter Property="FontWeight" Value="Bold" />
            </Style>
        </Window.Resources>

        <Button Style="{local:MultiStyle ButtonStyle GreenButtonStyle}" Content="Green Button" />
        <Button Style="{local:MultiStyle ButtonStyle RedButtonStyle}" Content="Red Button" />
        <Button Style="{local:MultiStyle ButtonStyle GreenButtonStyle BoldButtonStyle}" Content="green, bold button" />
        <Button Style="{local:MultiStyle ButtonStyle RedButtonStyle BoldButtonStyle}" Content="red, bold button" />

 * Notice how the syntax is just like using multiple CSS classes.
 * The current default style for a type can be merged using the "." syntax:

        <Button Style="{local:MultiStyle . GreenButtonStyle BoldButtonStyle}" Content="Bold Green Button" />

 */

namespace FlagstoneRe.WPF.Utilities.UI
{
    [MarkupExtensionReturnType(typeof(Style))]
    public class MultiStyleExtension : MarkupExtension
    {
        private string[] resourceKeys;

        /// <summary>
        /// Public constructor.
        /// </summary>
        /// <param name="inputResourceKeys">The constructor input should be a string consisting of one or more style names separated by spaces.</param>
        public MultiStyleExtension(string inputResourceKeys)
        {
            if (inputResourceKeys == null)
                throw new ArgumentNullException("inputResourceKeys");
            this.resourceKeys = inputResourceKeys.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            if (this.resourceKeys.Length == 0)
                throw new ArgumentException("No input resource keys specified.");
        }

        /// <summary>
        /// Returns a style that merges all styles with the keys specified in the constructor.
        /// </summary>
        /// <param name="serviceProvider">The service provider for this markup extension.</param>
        /// <returns>A style that merges all styles with the keys specified in the constructor.</returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            Style resultStyle = new Style();
            foreach (string currentResourceKey in resourceKeys)
            {
                object key = currentResourceKey;
                if (currentResourceKey == ".")
                {
                    IProvideValueTarget service = (IProvideValueTarget)serviceProvider.GetService(typeof(IProvideValueTarget));
                    key = service.TargetObject.GetType();
                }
                Style currentStyle = new StaticResourceExtension(key).ProvideValue(serviceProvider) as Style;
                if (currentStyle == null)
                    throw new InvalidOperationException("Could not find style with resource key " + currentResourceKey + ".");
                resultStyle.Merge(currentStyle);
            }
            return resultStyle;
        }
    }

    public static class MultiStyleMethods
    {
        /// <summary>
        /// Merges the two styles passed as parameters. The first style will be modified to include any 
        /// information present in the second. If there are collisions, the second style takes priority.
        /// </summary>
        /// <param name="style1">First style to merge, which will be modified to include information from the second one.</param>
        /// <param name="style2">Second style to merge.</param>
        public static void Merge(this Style style1, Style style2)
        {
            if(style1 == null)
                throw new ArgumentNullException("style1");
            if(style2 == null)
                throw new ArgumentNullException("style2");
            if(style1.TargetType.IsAssignableFrom(style2.TargetType))
                style1.TargetType = style2.TargetType;
            if(style2.BasedOn != null)
                Merge(style1, style2.BasedOn);
            foreach(SetterBase currentSetter in style2.Setters)
                style1.Setters.Add(currentSetter);
            foreach(TriggerBase currentTrigger in style2.Triggers)
                style1.Triggers.Add(currentTrigger);
            // This code is only needed when using DynamicResources.
            foreach(object key in style2.Resources.Keys)
                style1.Resources[key] = style2.Resources[key];
        }
    }
}
解决方案

I'm running into the same issue. Some additional information:

At runtime, the IServiceProvider value is of type "MS.Internal.Xaml.ServiceProviderContext".

In the Visual Studio Xaml Designer, the IServiceProvider value is of type "Microsoft.Expression.DesignModel.Core.InstanceBuilderOperations.InstanceBuilderServiceProvider".

Clearly, VS2010 is using classes from Expression Blend to provide better design-time behavior than VS2008 had - but at a price, because the Expression Blend classes don't have all the same information that the actual run-time system does.

MORE INFO: I tried inserting my own class that implements both IServiceProvider and IXamlSchemaContextProvider. Some calls get passed to the original IServiceProvider, and I provide a dummy (empty) XamlSchemaContext when requested. But I still get the same error.

Something inside WPF is encapsulating my IServiceProvider with another IServiceProvider type - but one that fails to implement IXamlSchemaContextProvider. I have no further ideas on how to resolve this.

这篇关于标记扩展'StaticResourceExtension'需要'IXamlSchemaContextProvider'在的IServiceProvider的ProvideValue实施的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-19 02:34