【问题标题】:How is a graphical element dynamically created in code compiled (.NET 5)? [closed]如何在编译的代码中动态创建图形元素(.NET 5)? [关闭]
【发布时间】:2021-01-30 13:31:46
【问题描述】:

XAML 项目文件被编译成 XAML 代码的二进制表示 - 二进制应用程序标记语言 (BAML)。然后将 BAML 代码作为资源嵌入到应用程序的最终程序集中 - exe 或 dll 文件。它涉及 XAML。但是,在应用程序运行时使用 C# 代码 (!) 创建的图形元素呢?

假设应用程序是一个空窗口:

<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 已经在读取的临时资源?谢谢

【问题讨论】:

  • 根本没有资源。元素被简单地创建并添加到可视化树中。
  • 我认为混淆可能在于按钮是什么。任何一种方法都会在内存中创建一个对象。这不需要编译,它是一个按钮对象或一个形状或其他任何东西。不是代码。有一个与按钮关联的模板,但这也用于创建对象。所以一个按钮有一个边框。如果你给它一个字符串作为内容,那么就会创建一个文本块并制作按钮的内容,并将它的文本属性设置为你的字符串。但是该按钮的任何代码都已编译,并且在该按钮对象中执行它是按钮的事情。

标签: c# wpf xaml compilation baml


【解决方案1】:

这是一个非常有趣的问题,我认为理解答案确实可以让您更深入地了解 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 时,编译器确实实际上会输出一些在构造函数中调用InitializeComponent 时执行的C# 代码;编译后可以在项目的obj目录下找到生成的文件。这就是 XAML 中的 x:Name'd 项如何成为可以在代码隐藏中引用的私有类成员的方式。 (这也是为什么你所有的UserControl 都是partial 类)。同样,Xamarin XAML 编译器具有编译 XAML 并将其作为 IL 直接注入程序集的选项(这是 C# 编译成的字节码);这或多或少是他们对 BAML 的回答。

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

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

【讨论】:

  • 大声笑,我很想知道匿名人士对此回答有何不满。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-10
  • 2018-05-29
  • 1970-01-01
  • 2019-01-14
  • 2019-12-11
相关资源
最近更新 更多