通过互操作加载 WPF window 时标记扩展不起作用
Markup Extension not working when WPF window is loaded through interop
我正在从 VB6 应用程序打开 WPF windows 作为向 .NET 迁移过程的一部分。 windows 在 C# class 库中。我得到一个 XamlParseException
(下面的堆栈跟踪),它仅在 XAML window 通过 COM 公开 class 加载时发生。 .NET 文件如下。
我没有使用下面的 classes 从 .NET 控制台应用程序加载 window 时遇到任何问题。但是从控制台应用程序加载它的代码几乎相同,只是在控制台应用程序中调用了 dispatcher.run()
。所以我不确定为什么互操作会改变这里的行为。
XamlParseException
表示 "The method or operation is not implemented"。堆栈跟踪位于此 post 的底部。它发生在 WindowA.xaml。我已经在它出现的那一行上面发表了评论。它发生在 <Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=MainBrush}"/>
项目文件
WindowWrapper.cs - 通过 COM
将 window 公开给 VB6 应用程序
[ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDual)]
public class WindowWrapper
{
//Note: This function is exposed to COM so that VB6 apps can call it.
public void OpenWindow()
{
Dispatcher.CurrentDispatcher.Invoke(() =>
{
var window = new WindowA();
window.ShowDialog();
});
//WPF will use the running Win32 dispatcher from VB6, so no need to call .Run() here
}
}
WindowA.xaml.cs
public partial class WindowA : Window
{
public WindowA()
{
// This is sort of a hacky way of getting a xaml dependency to load and
// getting Visual Studio to track the dependencies across projects
// So we don't have to manually copy or include them in some way.
// This reference to Localization manager will cause the proper assembly to load.
var twc = typeof(LocalizationManager); // Telerik.Windows.Controls.dll
InitializeComponent();
}
}
WindowA.xaml - Xaml 使用 COM Interop 时无法加载的文件
<Window x:Class="TelerikProject.WindowA"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Telerik Windows8 Theme files -->
<ResourceDictionary Source="pack://application:,,,/TelerikProject;component/Themes/System.Windows.xaml"/>
<ResourceDictionary Source="pack://application:,,,/TelerikProject;component/Themes/Telerik.Windows.Controls.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<telerik:RadButton Content="Test" Grid.Row="2" Width="75" Height="Auto" VerticalAlignment="Top" Margin="5"/>
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Grid.Row="0" Margin="5">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<!-- ERROR HAPPENS HERE. Probably isn't loading the MarkupExtension properly -->
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=MainBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=BasicBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=AccentBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=StrongBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=ValidationBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=MarkerBrush}"/>
</StackPanel>
</Border>
</Grid>
</Window>
XamlParseException
at System.Windows.Baml2006.Baml2006SchemaContext.ResolveBamlType(BamlType bamlType, Int16 typeId)
at System.Windows.Baml2006.Baml2006SchemaContext.GetXamlType(Int16 typeId)
at System.Windows.Baml2006.Baml2006SchemaContext.GetProperty(Int16 propertyId, XamlType parentType)
at System.Windows.Baml2006.Baml2006Reader.Process_PropertyWithConverter()
at System.Windows.Baml2006.Baml2006Reader.Process_OneBamlRecord()
at System.Windows.Baml2006.Baml2006Reader.Process_BamlRecords()
at System.Windows.Baml2006.Baml2006Reader.Read()
at System.Windows.Markup.WpfXamlLoader.TransformNodes(XamlReader xamlReader, XamlObjectWriter xamlWriter, Boolean onlyLoadOneNode, Boolean skipJournaledProperties, Boolean shouldPassLineNumberInfo, IXamlLineInfo xamlLineInfo, IXamlLineInfoConsumer xamlLineInfoConsumer, XamlContextStack\`1 stack, IStyleConnector styleConnector)
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at TelerikProject.WindowA.InitializeComponent() in <pathToProject>\TelerikProject\WindowA.xaml:line 1
更新
根据Rob Relyea的建议,我也试过在代码中调用这个。以下内容在两种情况下都可以正常工作。我希望我重新创建它是正确的。
var rect = new Rectangle();
rect.Width = 20;
rect.Height = 20;
var ext = new Windows8ResourceExtension();
ext.ResourceKey = (Windows8ResourceKey)(new Windows8ResourceKeyTypeConverter().ConvertFrom("AccentBrush"));
var resourceReferenceExpression = ext.ProvideValue(new MockServiceProvider(rect));
var type = resourceReferenceExpression.GetType();
var mi = type.GetMethod("GetValue", BindingFlags.NonPublic | BindingFlags.Instance);
rect.Fill = (Brush)mi.Invoke(resourceReferenceExpression, new object[] { rect, Shape.FillProperty });
并且 ProvideValue 需要一个 IServiceProvider 作为参数。我猜这会为它提供元素和它所应用的 属性,所以我嘲笑提供者提供我创建的矩形。 (这样对吗?)
public class MockServiceProvider : IServiceProvider
{
private Rectangle _rect;
public MockServiceProvider(Rectangle rect)
{
_rect = rect;
}
public object GetService(Type serviceType)
{
if(serviceType.Name == "IProvideValueTarget")
{
return new MockProviderTarget(_rect, Rectangle.FillProperty);
}
else
{
throw new NotImplementedException();
}
}
}
public class MockProviderTarget : IProvideValueTarget
{
private object _targetObject;
private object _targetProperty;
public MockProviderTarget(object targetObject, object targetProperty)
{
_targetObject = targetObject;
_targetProperty = targetProperty;
}
public object TargetObject {
get
{
return _targetObject;
}
}
public object TargetProperty {
get
{
return _targetProperty;
}
}
}
尝试从中取出 xaml。构建代码以创建该标记扩展实例,然后调用 providevalue()。我的猜测是当您以相同方式启动应用程序时会失败吗?可能 telerik 的代码依赖于随您的两种启动技术而改变的东西。
我正在从 VB6 应用程序打开 WPF windows 作为向 .NET 迁移过程的一部分。 windows 在 C# class 库中。我得到一个 XamlParseException
(下面的堆栈跟踪),它仅在 XAML window 通过 COM 公开 class 加载时发生。 .NET 文件如下。
我没有使用下面的 classes 从 .NET 控制台应用程序加载 window 时遇到任何问题。但是从控制台应用程序加载它的代码几乎相同,只是在控制台应用程序中调用了 dispatcher.run()
。所以我不确定为什么互操作会改变这里的行为。
XamlParseException
表示 "The method or operation is not implemented"。堆栈跟踪位于此 post 的底部。它发生在 WindowA.xaml。我已经在它出现的那一行上面发表了评论。它发生在 <Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=MainBrush}"/>
项目文件
WindowWrapper.cs - 通过 COM
将 window 公开给 VB6 应用程序[ComVisible(true),
ClassInterface(ClassInterfaceType.AutoDual)]
public class WindowWrapper
{
//Note: This function is exposed to COM so that VB6 apps can call it.
public void OpenWindow()
{
Dispatcher.CurrentDispatcher.Invoke(() =>
{
var window = new WindowA();
window.ShowDialog();
});
//WPF will use the running Win32 dispatcher from VB6, so no need to call .Run() here
}
}
WindowA.xaml.cs
public partial class WindowA : Window
{
public WindowA()
{
// This is sort of a hacky way of getting a xaml dependency to load and
// getting Visual Studio to track the dependencies across projects
// So we don't have to manually copy or include them in some way.
// This reference to Localization manager will cause the proper assembly to load.
var twc = typeof(LocalizationManager); // Telerik.Windows.Controls.dll
InitializeComponent();
}
}
WindowA.xaml - Xaml 使用 COM Interop 时无法加载的文件
<Window x:Class="TelerikProject.WindowA"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- Telerik Windows8 Theme files -->
<ResourceDictionary Source="pack://application:,,,/TelerikProject;component/Themes/System.Windows.xaml"/>
<ResourceDictionary Source="pack://application:,,,/TelerikProject;component/Themes/Telerik.Windows.Controls.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<telerik:RadButton Content="Test" Grid.Row="2" Width="75" Height="Auto" VerticalAlignment="Top" Margin="5"/>
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Center" VerticalAlignment="Bottom" Grid.Row="0" Margin="5">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<!-- ERROR HAPPENS HERE. Probably isn't loading the MarkupExtension properly -->
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=MainBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=BasicBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=AccentBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=StrongBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=ValidationBrush}"/>
<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=MarkerBrush}"/>
</StackPanel>
</Border>
</Grid>
</Window>
XamlParseException
at System.Windows.Baml2006.Baml2006SchemaContext.ResolveBamlType(BamlType bamlType, Int16 typeId)
at System.Windows.Baml2006.Baml2006SchemaContext.GetXamlType(Int16 typeId)
at System.Windows.Baml2006.Baml2006SchemaContext.GetProperty(Int16 propertyId, XamlType parentType)
at System.Windows.Baml2006.Baml2006Reader.Process_PropertyWithConverter()
at System.Windows.Baml2006.Baml2006Reader.Process_OneBamlRecord()
at System.Windows.Baml2006.Baml2006Reader.Process_BamlRecords()
at System.Windows.Baml2006.Baml2006Reader.Read()
at System.Windows.Markup.WpfXamlLoader.TransformNodes(XamlReader xamlReader, XamlObjectWriter xamlWriter, Boolean onlyLoadOneNode, Boolean skipJournaledProperties, Boolean shouldPassLineNumberInfo, IXamlLineInfo xamlLineInfo, IXamlLineInfoConsumer xamlLineInfoConsumer, XamlContextStack\`1 stack, IStyleConnector styleConnector)
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
at TelerikProject.WindowA.InitializeComponent() in <pathToProject>\TelerikProject\WindowA.xaml:line 1
更新
根据Rob Relyea的建议,我也试过在代码中调用这个。以下内容在两种情况下都可以正常工作。我希望我重新创建它是正确的。
var rect = new Rectangle();
rect.Width = 20;
rect.Height = 20;
var ext = new Windows8ResourceExtension();
ext.ResourceKey = (Windows8ResourceKey)(new Windows8ResourceKeyTypeConverter().ConvertFrom("AccentBrush"));
var resourceReferenceExpression = ext.ProvideValue(new MockServiceProvider(rect));
var type = resourceReferenceExpression.GetType();
var mi = type.GetMethod("GetValue", BindingFlags.NonPublic | BindingFlags.Instance);
rect.Fill = (Brush)mi.Invoke(resourceReferenceExpression, new object[] { rect, Shape.FillProperty });
并且 ProvideValue 需要一个 IServiceProvider 作为参数。我猜这会为它提供元素和它所应用的 属性,所以我嘲笑提供者提供我创建的矩形。 (这样对吗?)
public class MockServiceProvider : IServiceProvider
{
private Rectangle _rect;
public MockServiceProvider(Rectangle rect)
{
_rect = rect;
}
public object GetService(Type serviceType)
{
if(serviceType.Name == "IProvideValueTarget")
{
return new MockProviderTarget(_rect, Rectangle.FillProperty);
}
else
{
throw new NotImplementedException();
}
}
}
public class MockProviderTarget : IProvideValueTarget
{
private object _targetObject;
private object _targetProperty;
public MockProviderTarget(object targetObject, object targetProperty)
{
_targetObject = targetObject;
_targetProperty = targetProperty;
}
public object TargetObject {
get
{
return _targetObject;
}
}
public object TargetProperty {
get
{
return _targetProperty;
}
}
}
尝试从中取出 xaml。构建代码以创建该标记扩展实例,然后调用 providevalue()。我的猜测是当您以相同方式启动应用程序时会失败吗?可能 telerik 的代码依赖于随您的两种启动技术而改变的东西。