从 C++/CX 和 C# 使用 C# 组件

Consuming C# component from C++/CX and C#
2021-11-25
  •  译文(汉语)
  •  原文(英语)

我在 C++/CX 中创建了一个简单的控件 SimpleControl.xaml 定义为:

<UserControl ..  > // Attributes omitted for reading simplicity
<Grid>

 <Grid.RowDefinitions>
    <RowDefinition Height="40"/>
    <RowDefinition Height="30"/>
 <RowDefinition Height="30"/>
 </Grid.RowDefinitions>

 <Grid.ColumnDefinitions>
    <ColumnDefinition Width="100"/>
    <ColumnDefinition Width="*"/>
 </Grid.ColumnDefinitions>

    <Image x:Name="PersonaPicture" ... />
    <Border x:Name="PhotoTextBackdrop" ... />
    <TextBlock x:Name="PersonaName" .../>

</Grid>
</UserControl>

然后在使用 C++/CX 作为代码隐藏的文件"foo.xaml"中以下列方式使用此控件.SuperPanel 继承自 Windows.UI.Xaml.Controls.Panel 并在 TastyLib 组件(由该 C++/CX 组件使用)中定义.'fruity' 命名空间指向 TastyLib.TastyLib 组件是用 C# 编码的:

</fruity:SuperPanel>
    <local:SimpleControl x:Name="gPerson1" Grid.Row="0" Grid.Column="0" />
    <Rectangle Fill="SaddleBrown" Height="50" Width="50" Grid.Row="1" Grid.Column="0" />
    <UserControl Grid.Row="2" Grid.Column="0" />
</fruity:SuperPanel>

设置断点并查看 watch ,我观察到以下是面板的子项:

child[0] 是 Windows.UI.Xaml.UIElement,child[1] 是 Windows.UI.Xaml.Shapes.Rectangle,child[2] 是 Windows.UI.Xaml.Controls.UserControl

现在,在手表中,我期望第一个孩子是 SimpleControl,但它是一个 UIElement,这让我感到惊讶.那个是从哪里来的?为什么它将 SimpleControl 的祖先显示为 child[0] 而它仍然可以将 UserControl 识别为 child[2] ?

我在使用 TastyLib 的 C# 组件中重新创建了另一个 SimpleControl(所以这个 SimpleControl 也是用 C# 编写的,没有使用 C++/CX),并将该控件放在另一个 SuperPanel 中,与第一种情况完全一样(但这次全部使用 C#) . 在设置相同的断点并在监视窗口中查看时,我看到 child[0] 是我所期望的 - 一个 SimpleControl.在这种情况下:

child[0] 是 FooProject.SimpleControl,child[1] 是 Windows.UI.Xaml.Shapes.Rectangle 和 child[2] 是 Windows.UI.Xaml.Controls.UserControl

这种二分法的根本原因可能是什么?用 C++/CX 编写的控件的行为方式不应该与用 C# 编写的控件完全相同(当使用用 C# 编写的相同组件时)?我猜这与组件互操作性有关.有没有人遇到过类似的问题?

任何意见,将不胜感激.

非常感谢.

解决过程1

根据我所做的研究,问题是在用 C++/CX 编写的控件的情况下跨越了 winRT 边界,因此当 CLR 请求类型时,对象从其返回 Windows.UI.Xaml.UIElement GetRuntimeClassName 实现(为什么?).

在使用 C# 开发的控件的情况下,不会跨越 winRT 边界,并且一个 .NET 对象正在与另一个 .NET 对象对话,因此类型是已知的.

I have created a simple control SimpleControl.xaml in C++/CX defined as:

<UserControl ..  > // Attributes omitted for reading simplicity
<Grid>

 <Grid.RowDefinitions>
    <RowDefinition Height="40"/>
    <RowDefinition Height="30"/>
 <RowDefinition Height="30"/>
 </Grid.RowDefinitions>

 <Grid.ColumnDefinitions>
    <ColumnDefinition Width="100"/>
    <ColumnDefinition Width="*"/>
 </Grid.ColumnDefinitions>

    <Image x:Name="PersonaPicture" ... />
    <Border x:Name="PhotoTextBackdrop" ... />
    <TextBlock x:Name="PersonaName" .../>

</Grid>
</UserControl>

Then this control is used in the following manner in a file “foo.xaml” that uses C++/CX as a code behind. SuperPanel inherits from Windows.UI.Xaml.Controls.Panel and is defined in the TastyLib component (consumed by this C++/CX component). The 'fruity' namespace points to TastyLib. The TastyLib component is coded in C#:

</fruity:SuperPanel>
    <local:SimpleControl x:Name="gPerson1" Grid.Row="0" Grid.Column="0" />
    <Rectangle Fill="SaddleBrown" Height="50" Width="50" Grid.Row="1" Grid.Column="0" />
    <UserControl Grid.Row="2" Grid.Column="0" />
</fruity:SuperPanel>

Setting a breakpoint and looking at the watch , I observed the following to be the children of the panel:

child[0] was Windows.UI.Xaml.UIElement, child[1] was Windows.UI.Xaml.Shapes.Rectangle and child[2] was Windows.UI.Xaml.Controls.UserControl

Now, in the watch I was expecting the first child to be a SimpleControl, but instead it is a UIElement, which is surprising to me. Where did that come from? Why is it showing an ancestor of SimpleControl as child[0] while it can still recognize a UserControl as child[2] ?

I recreated another SimpleControl in a C# component that uses TastyLib (So this SimpleControl was also written in C# and did not use C++/CX), and put that control within another SuperPanel, exactly like the first case (but all in C# this time). On setting the same breakpoint and viewing in the watch window I saw child[0] to be what I was expecting - a SimpleControl. In this case:

child[0] was FooProject.SimpleControl, child[1] was Windows.UI.Xaml.Shapes.Rectangle and child[2] was Windows.UI.Xaml.Controls.UserControl

What could be the root cause of this dichotomy? Shouldn’t a control written in C++/CX behave the exact way as a control written in C# (when consuming the same component written in C#) ? I’m guessing that it’s something to do with component interoperability. Has anyone faced a similar problem?

Any advice would be appreciated.

Many thanks.

Solutions1

From the research I've done, the issue is that a winRT boundary is crossed in the case of the control written in C++/CX so when the CLR asks for the type, the object returns back Windows.UI.Xaml.UIElement from its GetRuntimeClassName implementation (why?).

In case of control developed using C#, no winRT boundry is crossed and a .NET object is speaking to another .NET object and hence the type is known.

转载于:https://stackoverflow.com/questions/15238501/consuming-c-sharp-component-from-c-cx-and-c-sharp

本人是.net程序员,因为英语不行,使用工具翻译,希望对有需要的人有所帮助
如果本文质量不好,还请谅解,毕竟这些操作还是比较费时的,英语较好的可以看原文

留言回复
我们只提供高质量资源,素材,源码,坚持 下了就能用 原则,让客户花了钱觉得值
上班时间 : 周一至周五9:00-17:30 期待您的加入