Ala*_*ain 6 c# wpf extension-methods xaml .net-4.0
我已经使用了几年的资源扩展在设计时在一个新的 .Net 4 项目中停止工作,并出现以下错误:
标记扩展“StaticResourceExtension”要求在 IServiceProvider 中为 ProvideValue 实现“IXamlSchemaContextProvider”。
扩展中的相关方法如下:
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;
}
Run Code Online (Sandbox Code Playgroud)
据推测,编译器给出了错误,因为当我调用时currentStyle = new StaticResourceExtension(key).ProvideValue(serviceProvider);
,我传递的 serviceProvider 缺少 IXamlSchemaContextProvider 信息。不知道它会从哪里来,我什至不知道标记扩展的服务提供者是如何设置的,我只是像这样使用它:
<Style x:Key="ReadOnlyTextCell" TargetType="{x:Type TextBlock}" BasedOn="{util:MultiStyle ReadOnlyCell TextCell}"/>
扩展的完整代码在这里:
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];
}
}
}
Run Code Online (Sandbox Code Playgroud)
我遇到了同样的问题。一些附加信息:
在运行时,IServiceProvider 值的类型为“MS.Internal.Xaml.ServiceProviderContext”。
在 Visual Studio Xaml 设计器中,IServiceProvider 值的类型为“Microsoft.Expression.DesignModel.Core.InstanceBuilderOperations.InstanceBuilderServiceProvider”。
显然,VS2010 使用 Expression Blend 中的类来提供比 VS2008 更好的设计时行为 - 但要付出一定的代价,因为 Expression Blend 类不具有与实际运行时系统相同的信息。
更多信息:我尝试插入自己的类来实现 IServiceProvider 和 IXamlSchemaContextProvider。一些调用会传递到原始 IServiceProvider,并且我会在请求时提供一个虚拟(空)XamlSchemaContext。但我仍然遇到同样的错误。
WPF 内部的某些内容正在使用另一种 IServiceProvider 类型封装我的 IServiceProvider - 但该类型无法实现 IXamlSchemaContextProvider。我对如何解决这个问题没有进一步的想法。
归档时间: |
|
查看次数: |
3036 次 |
最近记录: |