通过互操作

时间:2017-03-29 05:34:35

标签: wpf xaml vb6 interop

我从VB6应用程序打开WPF窗口,作为.NET迁移过程的一部分。窗口位于C#类库中。我得到一个XamlParseException(下面的堆栈跟踪),只有在通过暴露于COM的类加载XAML窗口时才会发生。它的.NET文件如下。

使用以下类从.NET控制台应用程序加载窗口时遇到任何问题。但是从控制台应用程序加载它的代码几乎相同,而不是在控制台应用程序中调用dispatcher.run()。所以我不确定为什么互操作会改变这里的行为。

XamlParseException说&#34;方法或操作没有实现&#34;。堆栈跟踪位于此帖的底部。它发生在WindowA.xaml中。我在上面发表的一行评论过。它发生在<Rectangle Width="20" Height="20" Fill="{telerik:Windows8Resource ResourceKey=MainBrush}"/>

项目文件

WindowWrapper.cs - 通过COM

将窗口暴露给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 - 使用COM Interop时无法加载的Xaml文件

<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;
        }
    }
}

1 个答案:

答案 0 :(得分:1)

尝试从中取出xaml。构建代码以创建该标记扩展实例,然后调用providevalue()。我的猜测是,当你以同样的方式启动应用程序时会失败吗?可能telerik的代码依赖于随着你的两种发射技术而改变的东西。

相关问题