65.9K
CodeProject 正在变化。 阅读更多。
Home

为 X11 编写 XAML 对话框应用程序

starIconstarIconstarIconstarIconstarIcon

5.00/5 (6投票s)

2014年10月10日

CPOL

17分钟阅读

viewsIcon

19698

downloadIcon

451

目前,主要的 Linux/Unix (X11) GUI 应用程序框架(GTK+、KDE)都不支持基于 XAML 的应用程序开发。Moonlight 项目(包括 XAML 支持)已于 2012 年 5 月 29 日停止。本文将介绍如何使用 Roma Widget Set (Xrw) 和 C# 来开发基于 XAML 的对话框应用程序。

引言

本文是一个实践教程,介绍如何使用 **Roma Widget Set** (Xrw) 和 XAML,以 MVVM (Model View ViewModel) 设计模式编写一个 X11 对话框界面(简单 GUI)应用程序。Roma Widget Set 是一个零依赖的 X11 GUI 应用程序框架(仅需要免费的 Mono 标准安装程序中的程序集和免费的 X11 发行版的库;它不特别需要 GNOME、KDE 或商业库),并且完全用 C# 实现。

据我所知,这是在 Moonlight 项目被放弃后,首次尝试利用 Xrw 为 X11 应用程序开发使用 XAML。

Roma Widget Set 和 XAML 实现都未完成。此示例应用程序旨在作为“概念验证”,并检查是否以及如何可能使用 XAML 创建基于 MVVM 设计模式的 X11 应用程序。

下一篇关于使用 Roma Widget Set 在 X11 上进行 XAML 开发的文章将是《用 XAML 为 X11 编写功能区应用程序》。

背景

动机

尽管 System.Windows.Forms 应用程序仍然存在,但越来越多的现有应用程序正在转向 XAML,并且在 Microsoft® Windows® 平台上,大多数新应用程序现在都是用 XAML 构建的。

尽管 XAML 给开发者带来了新的问题,例如

  • 冗余且冗长的语言语法,
  • 低效率导致更高的处理成本,
  • 为分层模型设计,而非为关系模型设计,需要额外的努力来表达重叠(非分层)关系,
  • 命名空间的使用导致处理和解释困难,以及
  • 一个本应简单的语言存在严重的歧义

但它拥有——除了很多其他优点之外——三个非常重要的优点。XAML

  • 是平台无关的,
  • 是纯文本,易于维护,并且
  • 强制实现 GUI 和业务逻辑的清晰分离和松耦合。

由于良好的文档可以尽量减少缺点带来的影响,因此优点就更加重要。为什么不将 XAML 用于 X11 应用程序开发,并通过一个好的教程来避免(由于相当陡峭的学习曲线)令人沮丧的初步体验呢?好的——让我们开始吧!

概念

要将 XAML 引入 X11 应用程序开发,需要克服一些挑战

  1. GUI 应用程序框架必须支持控件和其他框架元素的动态创建。
  2. XAML 语法应尽可能接近 Microsoft® 原始语法。这将
    • 允许在 X11 和 Windows® 之间转移已获得的知识和编写的 XAML 代码,并且
    • 支持 GUI 和业务逻辑的分离,以编写平台无关的代码。
  3. XAML 中定义的框架元素也必须可以通过 C# 代码访问。这是实现属性更改通知机制以实现从 ViewModel 到 View 的通知所必需的。
  4. GUI 应用程序框架必须支持适当的反射方法,以实现属性更改通知机制以实现从 View 到 ViewModel 的通知。

克服这些挑战的方法是

  1. 围绕 Roma Widget Set 的 XAML 包装器。XAML 包装器和 Xrw 完全用 C# 编写,并且可以利用动态语言特性。
  2. 自定义 XAML 解释器。这使得可以轻松地采用期望的语法和功能,使其尽可能接近 Microsoft® 原始语法。
  3. 单独创建的 XAML 预处理器,它动态生成部分类中与 XAML 中定义的那些部分相关联的那一部分。
  4. 为 Xrw 周围的 XAML 包装器实现复杂的泛型反射方法。

为了评估这些方法,应该实现一个基本的基于 XAML 的对话框应用程序。该示例应用程序是用 Mono Develop 在 C# 中编写的。它基于 Mono Develop 在代码编译前运行用户定义命令以运行 XAML 预处理器的功能。

焦点

本文旨在演示

  • 可以使用 XAML 定义一个带有某些控件的窗口,并且
  • 可以使用 XAML 将单击事件连接到按钮。

使用代码

示例应用程序是使用 Mono Develop 2.4.1 和 Mono 2.8.1 在 OPEN SUSE 11.3 Linux 32 位 EN 和 GNOME 桌面上编写的。将其移植到任何旧版本或新版本都不应成问题。示例应用程序的解决方案包含两个项目(完整的源代码可供下载)

  • XamlDialogApp 包含示例应用程序的源代码。
  • XamlPreprocessor 包含 XAML 预处理器的源代码。

该示例应用程序还通过了 Mono Develop 3.0.6 在 OPEN SUSE 12.3 Linux 64 位 DE 和 GNOME 桌面、IceWM、TWM 和 Xfce 上针对 Mono 3.0.4 的测试。

32 位和 64 位解决方案之间的唯一区别是某些 X11 特定数据类型的定义,正如在《用 Mono Develop 编写 Xlib - 第一部分:低级(概念验证)》一文中已经描述的那样。

Xlib/X11 窗口处理基于 X11Wrapper 程序集版本 0.7,它定义了 Xlib/X11 对 libX11.so 的调用的函数原型、结构和类型。该程序集是为《用 Mono Develop 编写 Xlib - 第一部分:低级(概念验证)》项目开发的,并在《使用 Roma Widget Set (C# X11) - 一个零依赖的 GUI 应用程序框架 - 基础》项目中得到了改进。

GUI 框架基于 Xrw 程序集版本 0.7,它定义了在 XAML 代码中使用的控件/小部件及其包装类(应尽可能接近 Microsoft® 原始代码)。该程序集是在《使用 Roma Widget Set (C# X11) - 一个零依赖的 GUI 应用程序框架 - 基础》项目中开发的。

建议:要使用 MonoDevelop 的类库文档快捷键 (F1),必须安装“mono-tools”软件包。

图像显示了使用 XrwTheme.GeneralStyle.WinMidori 的示例应用程序。

示例应用程序的业务功能包括

  • 将 Base64 编码的文本(*.txt)解码为二进制图像文件(*.decoded.bmp),
  • 将二进制图像文件(*.bmp)编码为 Base64 编码的文本(*.encoded.txt),以及
  • 使用系统的默认文本编辑器打开最近编码的文件

以演示对话框界面应用程序的实际用例。

默认图像格式(即默认文件名扩展名)是 BMP。其他文件格式也应该可以工作,但需要事后更改文件名扩展名。

Windows 版本是与实现尽可能接近 Microsoft® 原始 XAML 代码并行开发的,它使用了 System.Convert.FromBase64String()System.Convert.ToBase64String()。由于 Mono 中这些方法的实现存在 bug,因此此示例应用程序的 Linux/Unix 版本改用了 X11.AlternativeBase64.Decode()X11.AlternativeBase64.Encode()

分步说明

项目设置

首先,我们需要一个新的空 C# 项目。不需要额外的功能。推荐使用 MONO / .NET 3.5 或更高版本作为运行时版本。

项目引用必须包括标准程序包 SystemSystem.CoreSystem.DrawingSystem.Xml 以及程序集(或项目)X11WrapperXrw。项目需要七个初始文件,可以任意命名。为了尽可能接近 Microsoft® 原始代码,建议使用

  • App.xaml 用于应用程序的类 XAML 定义,
  • App.xaml.cs 用于应用程序的类(手动)实现/代码隐藏,
  • MainModel.cs 用于主视图的 MVVM 数据模型,
  • MainView.xaml 用于(对话框窗口)主视图的类 XAML 定义,
  • MainView.xaml.cs 用于(对话框窗口)主视图的类(手动)实现/代码隐藏,
  • MainViewModel.cs 用于主视图的 MVVM ViewModel,以及
  • 应用程序的图标文件。

最后,必须将 XAML 预处理器包含到项目中。这通过一个用户定义的命令来实现,该命令在编译前执行。

预处理器是解决方案的一部分,位于 XamlDialogApp 项目文件夹的相对路径 '../XamlPreprozessor/bin/Debug/XamlPreprozessor.exe'。可以随意更改位置。必须将执行命令的当前工作目录设置为 XamlDialogApp 项目文件夹,否则预处理器可能会检查错误的文件夹。

目前预处理器不检查子文件夹。但这对于此示例来说没问题。

应用程序文件内容

XAML (App.xaml)

要查看的第一个 XAML 文件是 App.xaml

<Application    x:Class="XamlDialogApp.App"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                StartupUri="MainView.xaml"
                Style="WinMidori">
    <!-- Supported styles are: WinClassic, WinLuna, WinRoyale, WinMidori, Gtk2Clearlooks -->
    <Application.Resources>
    </Application.Resources>
</Application>

除了属性 Style="WinLuna" 之外,XAML 代码完全兼容 Microsoft®。或者,可以在 App.xaml.cs 中设置样式,以避免这种不兼容性。

Application 将由以下方式定义:

  • 根节点名为 Application此节点是必需的。 XAML 处理依赖于节点名称 Application
  • x:Class 属性定义了应用程序的命名空间名称(XamlDialogApp)和类名(App)。此属性是必需的。 强烈建议定义命名空间和类。XAML 处理依赖于属性名称 x:Class。属性名称 x:Class 是一个 XAML 扩展,定义在 http://schemas.microsoft.com/winfx/2006/xaml 命名空间中。
  • xmlnsxmlns:x 属性目前未被评估,仅作为 Microsoft® 兼容性的一部分包含在 XAML 代码中。
  • StartupUri 属性定义了启动 UI 的 XAML 文件 URI,对于此示例是 MainView.xaml此属性是必需的。 XAML 处理依赖于属性名称 StartupUri
  • Style 属性定义了 Xrw 用于显示 UI 的主题。此属性是可选的。
  • Application.Resources 节点目前未被评估。此属性是可选的。

代码隐藏 (App.xaml.cs)

对应的 C# 代码隐藏文件是 App.xaml.cs

using System;
using Xrw;
using XrwXAML;

namespace XamlDialogApp
{
    /// <summary>This is the application's main class.</summary>
    /// <remarks>It must be inherited from XrwXAML.Application and
    /// contain a Main method to start the application.</remarks>
    public partial class App : XrwXAML.Application
    {
        /// <summary>The application starter method.</summary>
        /// <returns>Zero on success, nonzero otherwise.<see cref="System.Int32"/></returns>
        public static int Main ()
        {
            // Delegate the hard work to the base class.
            return Main (System.Reflection.Assembly.GetExecutingAssembly());
        }

        /// <summary>The public constructor.</summary>
        public App ()
        {
           this.InitializeComponent();
        }
        
    }
}

请注意 App 类定义为 partial class!这一点很重要,因为 XAML 预处理器将根据 App.xaml 中的 XAML 代码生成 App 类的第二部分。

主视图文件内容

XAML (MainView.xaml)

要查看的第二个 XAML 文件是 MainView.xaml

<Window         x:Class="XamlDialogApp.MainView"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:src="clr-namespace:XamlDialogApp"
                DataContext="src:MainViewModel"
                Name="MainWindow" Title="XAML dialog application"
                Width="650" Height="400" Icon="XrwIcon16.bmp">
    <Window.Resources>
    </Window.Resources>
    <Grid Name="MainGrid">
        <Grid.Resources>
            <!-- <src:MainViewModel x:Key="mainViewDataSource" /> -->
        </Grid.Resources>
        <Grid.Datacontext>
            <!-- <Binding Source="{StaticResource mainViewDataSource}"/> -->
        </Grid.Datacontext>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="12"/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition Width="20"/>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition Width="12"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="12"/>
            <RowDefinition Height="28"/>
            <RowDefinition Height="12"/>
            <RowDefinition Height="28"/>
            <RowDefinition Height="50"/>
            <RowDefinition Height="28"/>
            <RowDefinition Height="12"/>
            <RowDefinition Height="28"/>
            <RowDefinition Height="12"/>
            <RowDefinition Height="68"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="12"/>
            <RowDefinition Height="32"/>
        </Grid.RowDefinitions>
        <TextBox Name="DecodeSourcePath" Grid.Column="1" Grid.Row="1" Text=""
                 BorderThickness="2" IsEnabled="false" />
        <TextBox Name="DecodeTargetPath" Grid.Column="1" Grid.Row="3" Text=""
                 BorderThickness="2" IsEnabled="false" />
        <Button Name="Decode" Grid.Column="3" Grid.Row="1" Grid.RowSpan="3" Click="Decode_Click" >
            <TextBlock Text="Decode Base64 to BMP/PNG" TextWrapping="Wrap"/>
        </Button>
        <TextBox Name="EncodeSourcePath" Grid.Column="1" Grid.Row="5" Text=""
                 BorderThickness="2" IsEnabled="false" />
        <TextBox Name="EncodeTargetPath" Grid.Column="1" Grid.Row="7" Text=""
                 BorderThickness="2" IsEnabled="false" />
        <Button Name="Encode" Grid.Column="3" Grid.Row="5" Grid.RowSpan="3" Click="Encode_Click" >
            <TextBlock Text="Encode BMP/PNG to Base64" TextWrapping="Wrap"/>
        </Button>
        <Label Name="EncodeData" Content="" Grid.Column="1" Grid.Row="9" Grid.RowSpan="2"
              BorderThickness="2" />
        <Button  Name="Open" Grid.Column="3" Grid.Row="9" Click="OpenResult_Click" >
            <TextBlock Text="Open result in a text editor" TextWrapping="Wrap"/>
        </Button>
        <Label Name="State" Content="O.K." Grid.Column="0" Grid.Row="12" Grid.ColumnSpan="5"
               BorderThickness="2" />
    </Grid>
</Window>

完整的 XAML 代码与 Microsoft® 完全兼容。

Window 将由以下方式定义:

  • 根节点名为 Window此节点是必需的。 XAML 处理依赖于节点名称 Window
  • x:Class 属性定义了主视图的命名空间名称(XamlDialogApp)和类名(MainView)。此属性是必需的。 强烈建议定义命名空间和类。XAML 处理依赖于属性名称 x:Class。属性名称 x:Class 是一个 XAML 扩展,定义在 http://schemas.microsoft.com/winfx/2006/xaml 命名空间中。
  • xmlnsxmlns:x 属性目前未被评估,仅作为 Microsoft® 兼容性的一部分包含在 XAML 代码中。
  • xmlns:src 属性定义了本地源代码资源的命名空间。此属性是推荐的,如果任何属性值使用前缀 src: 作为引用,则为必需的。 XAML 处理依赖于后缀 :src。属性值的语法必须是 clr-namespace:<namespace name>。这样定义的命名空间可以通过前缀 src: 在属性值中引用。
  • DataContext 属性定义了默认/备用数据上下文,对于此示例是 src:MainViewModel此属性是可选的。 DataContext 属性目前未被评估。
  • Name 属性定义了类实例名称,可用于唯一标识类实例。此属性是必需的。 类实例名称不能与类类型名称相同!
  • Title 属性定义了窗口标题。此属性是可选的。
  • Width 属性定义了初始窗口宽度。此属性是可选的。
  • Height 属性定义了初始窗口高度。此属性是可选的。
  • Icon 属性定义了窗口图标。此属性是可选的。
  • Window.Resources 节点目前未被评估。此节点是可选的。

Window 的根(控件几何)管理器控件是 Grid,将由以下方式定义:

  • Name 属性定义了类实例的名称,可用于唯一标识该类实例。此属性是推荐的,如果该类实例需要通过 C# 代码访问,则是必需的。
  • Grid.Resources 节点目前未被评估。此节点是可选的。
  • Grid.Datacontext 节点目前未被评估。此节点是可选的。
  • Grid.ColumnDefinitions 节点连接了列定义。此节点是必需的。
    - Grid.ColumnDefinition 节点定义了一个网格列。此节点是必需的,至少一次。
       - Width 属性定义了网格列宽度。此属性是必需的 正整数被解释为像素宽度。星号被解释为动态宽度。
  • Grid.RowDefinitions 节点连接了行定义。此节点是必需的。
    - Grid.RowDefinition 节点定义了一个网格行。此节点是必需的,至少一次。
       - Height 属性定义了网格行高度。此属性是必需的。 正整数被解释为像素高度。星号被解释为动态高度。
  • Grid 节点可以包含定义子控件的节点,这些子控件将由网格布局。

Grid 控件包含 TextBox 控件作为子控件,它们将由以下方式定义:

  • Name 属性定义了类实例的名称,可用于唯一标识该类实例。此属性是推荐的,如果该类实例需要通过 C# 代码访问,则是必需的。
  • Grid.Column 属性定义了控件在网格中应放置的从零开始的列索引。默认值为 0。此属性对于网格子项是推荐的,但对于放置在网格非第 0 列的控件是必需的。 索引不得超过可用网格列数。
  • Grid.Row 属性定义了控件在网格中应放置的从零开始的行索引。默认值为 0。此属性对于网格子项是推荐的,但对于放置在网格非第 0 行的控件是必需的。 索引不得超过可用网格行数。
  • Grid.ColumnSpan 属性定义了控件在网格中应跨越的列数。此属性对于网格子项是可选的,但对于跨越多个网格列的控件是必需的。 忽略此属性或将其设置为“0”或“1”是等效的。跨度不得超过可用网格列数。
  • Grid.RowSpan 属性定义了控件在网格中应跨越的行数。此属性对于网格子项是可选的,但对于跨越多个网格行的控件是必需的。 忽略此属性或将其设置为“0”或“1”是等效的。跨度不得超过可用网格行数。
  • Text 属性定义了要显示的文本。此属性是可选的。
  • BorderThickness 属性定义了控件边框的宽度。此属性是可选的。
  • IsEnabled 属性定义了控件的敏感度。此属性是可选的。 默认为 true。

Grid 控件包含 Button 控件作为子控件,它们将由以下方式定义:

  • Name 属性定义了类实例的名称,可用于唯一标识该类实例。此属性是推荐的,如果该类实例需要通过 C# 代码访问,则是必需的。
  • Grid.Column 属性定义了控件在网格中应放置的从零开始的列索引。默认值为 0。此属性对于网格子项是推荐的,但对于放置在网格非第 0 列的控件是必需的。 索引不得超过可用网格列数。
  • Grid.Row 属性定义了控件在网格中应放置的从零开始的行索引。默认值为 0。此属性对于网格子项是推荐的,但对于放置在网格非第 0 行的控件是必需的。 索引不得超过可用网格行数。
  • Grid.ColumnSpan 属性定义了控件在网格中应跨越的列数。此属性对于网格子项是可选的,但对于跨越多个网格列的控件是必需的。 忽略此属性或将其设置为“0”或“1”是等效的。跨度不得超过可用网格列数。
  • Grid.RowSpan 属性定义了控件在网格中应跨越的行数。此属性对于网格子项是可选的,但对于跨越多个网格行的控件是必需的。 忽略此属性或将其设置为“0”或“1”是等效的。跨度不得超过可用网格行数。
  • Content 属性定义了要显示的文本。此属性是可选的。也可以使用嵌套的 TextBlock 节点。 此属性的 Microsoft® 原始实现无法提供换行。
    - 嵌套的 TextBlock 节点定义了要显示的文本。此节点是可选的。 它可以提供换行。
       - Text 属性定义了文本字符串。此属性是必需的。
       - TextWrapping 属性定义了文本换行。此属性是可选的
  • Click 属性定义了单击事件委托。此属性是可选的。 目前,委托必须定义在 Window(代码隐藏)的类代码中,该控件是其子/孙控件。

Grid 控件包含 Label 控件作为子控件,它们将由以下方式定义:

  • Name 属性定义了类实例的名称,可用于唯一标识该类实例。此属性是推荐的,如果该类实例需要通过 C# 代码访问,则是必需的。
  • Grid.Column 属性定义了控件在网格中应放置的从零开始的列索引。默认值为 0。此属性对于网格子项是推荐的,但对于放置在网格非第 0 列的控件是必需的。 索引不得超过可用网格列数。
  • Grid.Row 属性定义了控件在网格中应放置的从零开始的行索引。默认值为 0。此属性对于网格子项是推荐的,但对于放置在网格非第 0 行的控件是必需的。 索引不得超过可用网格行数。
  • Grid.ColumnSpan 属性定义了控件在网格中应跨越的列数。此属性对于网格子项是可选的,但对于跨越多个网格列的控件是必需的。 忽略此属性或将其设置为“0”或“1”是等效的。跨度不得超过可用网格列数。
  • Grid.RowSpan 属性定义了控件在网格中应跨越的行数。此属性对于网格子项是可选的,但对于跨越多个网格行的控件是必需的。 忽略此属性或将其设置为“0”或“1”是等效的。跨度不得超过可用网格行数。
  • Content 属性定义了要显示的文本。此属性是可选的
  • BorderThickness 属性定义了控件边框的宽度。此属性是可选的。

代码隐藏 (MainView.xaml.cs)

对应的 C# 代码文件是 MainView.xaml.cs。它包含所有三个 Button 控件的 Click 委托。

using System;
using System.IO;

using X11;
using Xrw;
using XrwXAML;

namespace XamlDialogApp
{
    /// <summary>The main window of the application. This class must be derived from XrwXAML.Window.
    /// It must be a partial class. The second part of the class will be autogenerated and named
    /// '*.generated.cs'.</summary>
    public partial class MainView : XrwXAML.Window
    {
        
        /// <summary>The default constructor.</summary>
        public MainView ()
            : base (-1, -1)
        {
            // InitializeComponent () and InitializeComponentGenerated()
            // will be called after construction by generated code!
        }
        
        /// <summary>Process the "Decode" button click event.</summary>
        /// <param name="sender">The event source.<see cref="System.Object"/></param>
        /// <param name="e">The event data.<see cref="RoutedEventArgs"/></param>
        private void Decode_Click(object sender, RoutedEventArgs e)
        {
            ...
        }
        
        /// <summary>Process the "Encode" button click event.</summary>
        /// <param name="sender">The event source.<see cref="System.Object"/></param>
        /// <param name="e">The event data.<see cref="RoutedEventArgs"/></param>
        private void Encode_Click(object sender, RoutedEventArgs e)
        {
            ...
        }
        
        /// <summary>Process the "Open" button click event.</summary>
        /// <param name="sender">The event source.<see cref="System.Object"/></param>
        /// <param name="e">The event data.<see cref="RoutedEventArgs"/></param>
        private void OpenResult_Click(object sender, RoutedEventArgs e)
        {
            if (!string.IsNullOrEmpty (EncodeTargetPath.Text))
                System.Diagnostics.Process.Start (EncodeTargetPath.Text);
        }
        
        /// <summary>Decode with Base64.</summary>
        /// <param name="sourceStream">The source to decode.<see cref="Stream"/></param>
        /// <param name="targetStream">The decoded target.<see cref="Stream"/></param>
        /// <param name="message">The message describing the success.<see cref="System.String"/></param>
        /// <returns>True on success, or false otherwise.<see cref="System.Boolean"/></returns>
        public bool DecodeBase64FromStream(Stream sourceStream, Stream targetStream, out string message)
        {
            ...
        }
        
        /// <summary>Encode with Base64.</summary>
        /// <param name="sourceStream">The source to encode.<see cref="Stream"/></param>
        /// <param name="targetStream">The encoded target.<see cref="Stream"/></param>
        /// <param name="message">The message describing the success.<see cref="System.String"/></param>
        /// <returns>True on success, or false otherwise.<see cref="System.Boolean"/></returns>
        public bool EncodeBase64FromStream(Stream sourceStream, Stream targetStream, out string message)
        {
            ...
        }
        
    }
}

请注意 MainView 类定义为 partial class!这一点很重要,因为 XAML 预处理器将根据 MainView.xaml 中的 XAML 代码生成 MainView 类的第二部分。

预处理器代码生成

在项目首次编译期间,预处理器首先从 App.xamlMainView.xml 生成部分类文件 App.generated.csMainView.generated.cs。预处理器将日志消息写入标准输出,可以在构建输出中查看。

要继续进行此示例,必须将生成的初始文件包含到项目中。否则,Mono Develop 将不会将文件包含到编译中,并且部分类 AppMainView 的生成部分将丢失。(这就是为什么第一次编译总是会产生错误的原因。)

 

生成的 *.generated.cs 文件与 Microsoft® 的文件不兼容

  • Microsoft® 的文件名为 *.g.cs
  • Microsoft® 的文件在项目中被隐藏(但 Mono 的文件必须包含在项目中)。
  • 文件内容完全不同。

现在可以逐步扩展功能,编译将生成可执行程序集。

关注点

能否使用 XAML 创建基于 MVVM 设计模式的 X11 应用程序?是的,可以!而且很有趣。因此,这不会是最后一篇关于 X11 XAML 编程的文章。

自 2014 年 10 月 29 日起,文章《用 XAML 为 X11 编写功能区应用程序》继续讨论 XAML 主题。
自 2014 年 11 月 23 日起,文章《使用大量数据绑定和零代码用 XAML 为 X11 编写应用程序》继续讨论 XAML 主题。
自2015年2月2日起,文章为 X11 编写 XAML 计算器应用程序延续了 XAML 主题。

历史

第一个版本是 2014 年 10 月 10 日。
第一个审阅版本来自 2014 年 10 月 29 日。
第二个审阅版本来自 2014 年 11 月 23 日。
第三个审阅版本来自 2015 年 2 月 19 日。

© . All rights reserved.