如何在代码编译(.NET 5)中动态创建图形元素?

How is a graphical element dynamically created in code compiled (.NET 5)?

XAML 项目文件被编译成 XAML 代码的二进制表示 - 二进制应用程序标记语言 (BAML)。然后将 BAML 代码作为资源嵌入到应用程序的最终程序集中 - exe 或 dll 文件。它涉及 XAML。但是,当应用程序处于 运行?

时,在 C# 代码 (!) 中创建的图形元素又如何呢?

假设应用程序是空的 window:

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<StackPanel x:Name="WindowStackPanel">
<Button Click="CreateButtonEvent" Content="I was created at compile time" />
</StackPanel>

</Window>

这个XAML被编译成可执行资源。

在鼠标事件中,我添加了新按钮 - 是一个图形元素,它在构建应用程序期间未编译到 BAML 中:

private void CreateButtonEvent(object sender, RoutedEventArgs e)
{
    WindowStackPanel.Children.Add(new Button() { Content = "Where was I created?" });
}

在这方面,问题是:当我在 C# 代码(而不是 XAML 代码)中创建一个图形项(按钮)时,应用程序是 运行,技术上会发生什么?它是写入由 BAML 创建的共享资源,还是创建 JIT 已经在读取的自己的临时资源?谢谢

这是一个非常有趣的问题,我认为理解答案确实可以让您更深入地了解 WPF(以及 UWP 或 Xamarin)是如何在幕后工作的。

本质上,XAML 有一个简单的功能——告诉框架如何构建可视化树。因此,在 XAML 中可以完成的任何事情都可以转换为 C#;我想不出一个例外。举个例子:

<StackPanel x:Name="WindowStackPanel">
     <Button Click="CreateButtonEvent" Content="I was created at compile time" />
</StackPanel>

可以写成:

var sp = new StackPanel() { Name = "WindowStackPanel" };
var button = new Button() { Content = "I was created at compile time" };
button.Click += CreateButtonEvent;
sp.Children.Add(button);

这只是做同一件事的两种不同方式。

理论上,XAML 编译器可以只输出 C# 代码,然后您可以将其包含并编译到您的项目中,您的应用程序将完全 以与它相同的方式工作现在。实际上,例如,当您创建 UserControl 时,编译器 确实 实际上输出了一些 C# 代码,这些代码在构造函数中调用 InitializeComponent 时执行;编译后可以在项目的obj目录下找到生成的文件。这就是您的 XAML 中的 x:Name 项如何成为您可以在代码隐藏中引用的私有 class 成员的方式。 (这也是为什么你所有的 UserControl 都是 partial classes)。同样,Xamarin XAML 编译器有一个选项可以编译 XAML 并将其作为 IL(即 C# 编译成的字节码)直接注入程序集;这或多或少是他们对 BAML 的回答。

甚至可以使用很少使用的 FrameworkElementFactory 通过 C# 创建模板。 (我不推荐它,但它可以做到!)如果你真的想要获得技术并进入杂草,FrameworkElementFactory实际上是在 BAML 时使用的在运行时处理以构建可视化树。

因此回到您的直接问题,在 XAML 中声明某些内容实际上并没有创建它。它为框架创建 指令 ,允许它在运行时创建对象。因此,一切都是在运行时创建的;一些通过 XAML 编译为 BAML,一些通过 XAML 编译为 C#,还有一些直接通过 C#。因此,通过 XAML 或通过您的 C# 代码添加按钮或任何其他类型的视觉元素最终没有区别。这完全取决于什么最适合您的用例。