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

为 X11 编写具有海量数据绑定和零代码的 XAML 应用程序

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (5投票s)

2014 年 11 月 22 日

CPOL

10分钟阅读

viewsIcon

18112

downloadIcon

244

目前,所有主要的 Linux/Unix (X11) GUI 应用程序框架 (GTK+, KDE) 都不支持基于 XAML 的应用程序开发。Moonlight 项目 (包括 XAML 支持) 已于 2012 年 5 月 29 日被放弃。本文评述了一个利用大量数据绑定和零代码的 XAML 应用程序。

下载 XamlFontApp_X11_32.zip
下载 XamlFontApp_X11_64.zip
下载 XamlFontApp_Win7.zip

引言

本文是一个案例研究,介绍如何使用 Roma Widget Set (Xrw) 编写一个基于 MVVM (Model View ViewModel) 设计模式的 X11 应用程序 (利用大量数据绑定和零代码),并使用 XAMLRoma Widget Set 是一个零依赖的 X11 GUI 应用程序框架 (仅需要免费的 Mono 标准安装程序集和免费 X11 发行版的库;它不特别需要 GNOME、KDE 或商业库),并且完全用 C# 实现。

本文延续了“为 X11 编写 XAML 对话框应用程序”和“为 X11 编写 XAML 功能区应用程序”的工作。据我所知,这是在 Moonlight 被放弃后,首次尝试使用 XAML 进行 X11 应用程序开发 (利用 Xrw)。

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

由于这是第三次尝试使用 XAML 进行 X11 应用程序开发并已成功,未来将有更多关于使用 Roma Widget Set 在 X11 上进行 XAML 开发的文章。

背景

使用 XAML 进行 X11 应用程序开发的动机和一般概念已在“为 X11 编写 XAML 对话框应用程序”一文中解释。

焦点

第一个文章 为 X11 编写 XAML 对话框应用程序 演示了使用 XAML

  • 定义一个包含一些控件的窗口,并且
  • 将点击事件连接到按钮上,

第二篇文章“为 X11 编写 XAML 功能区应用程序”演示了使用 XAML 如何

  • 定义一个包含 Ribbon 命令界面的窗口,
  • 定义静态窗口资源(本示例有一个资源转换器和一个 ModelView),
  • 将 ModelView 作为静态资源分配给控件的数据上下文,
  • 将资源转换器作为静态资源应用于控件的属性,
  • 通过“RelayCommand”方法将命令绑定到按钮,
  • 将控件属性绑定到数据上下文,并且
  • 可以通过 INotifyPropertyChanged 接口更新控件,

本文将演示 XAML 可以实现:

  • 海量数据绑定可以提供有用的功能,并且
  • 可以定义一个零代码后端的应用程序。

使用代码

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

  • XamlFontApp 包含示例应用程序的源代码。
  • 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,该程序集定义了 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”软件包。

第一张图片显示了示例应用程序在 OPEN SUSE 11.3 Linux 32 位 EN 和 GNOME 桌面上的样子。

第二张图片显示了示例应用程序在 OPEN SUSE 12.3 Linux 64 位 DE 和 Xfce 上的样子。

第三张图片显示了示例应用程序在 Windows® 7 64 位版本上的样子。

本示例应用程序提供了一个字体系列选择列表、一个字形选择列表和一个字体大小滑块。任何字体更改将立即在预览文本中显示。

本示例应用程序基于 Norris Cheng 的文章 Pure XAML Font Choose 中的思想。具体的挑战在于为 X11 实现零代码后端的完整功能。

逐步演示

项目设置应用程序文件上下文 (除主题外) 和预处理器代码生成步骤与“为 X11 编写 XAML 对话框应用程序”中的完全相同。如果需要从头开始创建新解决方案,请参考该文章。

主视图文件上下文

XAML (MainView.xaml)

首先是窗口的 XAML 文件。

<Window         x:Class="XamlFontApp.MainView"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:src="clr-namespace:XamlFontApp"
                DataContext="src:MainViewModel"
                Name="MainWindow" Title="XAML font application"
                Width="750" Height="400" Icon="XrwIcon16.bmp">
    <Window.Resources>
    </Window.Resources>
    <Grid Name="MainGrid" Background="#FFEBEBEB">
        <Grid.Resources>
            <!-- <src:MainViewModel x:Key="mainViewDataSource" /> -->
        </Grid.Resources>
        <Grid.Datacontext>
            <!-- <Binding Source="{StaticResource mainViewDataSource}"/> -->
        </Grid.Datacontext>
        <Grid.RowDefinitions>
            <RowDefinition Height="10"/>
            <RowDefinition Height="28"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="28"/>
            <RowDefinition Height="10"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="2*"/>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="10"/>
            <ColumnDefinition Width="1*"/>
            <ColumnDefinition Width="10"/>
        </Grid.ColumnDefinitions>
        
        <Label Name="FontFamiliesLabel" Grid.Column="1" Grid.Row="1" FontSize="14"
              FontWeight="Bold" Content="Font Family" Background="#FFEBEBEB" />
        <ListView Name="FontFamiliesListView" Grid.Column="1" Grid.Row="2"
                  ItemsSource="{x:Static Fonts.SystemFontFamilies}" >
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="Source"
                                        DisplayMemberBinding="{Binding Source}" />
                        <GridViewColumn Header="Baseline"
                                        DisplayMemberBinding="{Binding Baseline}" />
                        <GridViewColumn Header="LineSpacing"
                                        DisplayMemberBinding="{Binding LineSpacing}" />
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
        <Label Name="SelectedFontFamilyLabel" Grid.Column="1" Grid.Row="3"
               Content="{Binding SelectedItem.Source, ElementName=FontFamiliesListView, Mode=OneWay}"
               Background="#FFEBEBEB" />
        
        <Label Name="FamilyTypefacesLabel" Grid.Column="3" Grid.Row="1"
               FontSize="14" FontWeight="Bold" Content="Family Typefaces" Background="#FFEBEBEB" />
        <ListView Name="FamilyTypefacesListView" Grid.Column="3" Grid.Row="2"
                  ItemsSource="{Binding SelectedItem.FamilyTypefaces,
                                ElementName=FontFamiliesListView, Mode=OneWay}" >
            <ListView.View>
                <GridView>
                    <GridView.Columns>
                        <GridViewColumn Header="Style" DisplayMemberBinding="{Binding Style}" />
                        <GridViewColumn Header="Weight" DisplayMemberBinding="{Binding Weight}" />
                        <GridViewColumn Header="Stretch" DisplayMemberBinding="{Binding Stretch}" />
                    </GridView.Columns>
                </GridView>
            </ListView.View>
        </ListView>
        <Label Name="SelectedFamilyTypefacesLabel" Grid.Column="3" Grid.Row="3"
               Content="{Binding SelectedItem.Style, ElementName=FamilyTypefacesListView, Mode=OneWay}"
               Background="#FFEBEBEB" />
        
        <Slider Name="FontSizeSlider" Grid.Column="5" Grid.Row="1" Orientation="Horizontal"
                Minimum="6" Value="12" Maximum="72" SmallChange="1" LargeChange="8" />
        <TextBlock Name="TextSimulation" Grid.Column="5" Grid.Row="2"
                   Text="The quick brown fox jumps over the lazy dog."
                 FontFamily="{Binding SelectedItem.Source, ElementName=FontFamiliesListView}"
                 FontWeight="{Binding SelectedItem.Weight, ElementName=FamilyTypefacesListView}"
                 FontStretch="{Binding SelectedItem.Stretch, ElementName=FamilyTypefacesListView}"
                 FontStyle="{Binding SelectedItem.Style, ElementName=FamilyTypefacesListView}"
                 FontSize="{Binding Value, ElementName=FontSizeSlider}" TextWrapping="Wrap"
                 Background="#FFF8F8F8" />
        <Label Name="FontSizeLabel" Grid.Column="5" Grid.Row="3" Background="#FFEBEBEB"
               Content="{Binding Value, ElementName=FontSizeSlider, Mode=OneWay}" />
    </Grid>
</Window>

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

与“为 X11 编写 XAML 功能区应用程序”相比,仅讨论增强功能和差异。

Label 将 (除已知功能外) 由以下方式定义:

  • Background 属性定义背景颜色。此属性是可选的。该属性的语法是十六进制值 #AARRGGBB,其中 AA 代表 alpha,RR 代表红色,GG 代表绿色,BB 代表蓝色。目前 alpha 值尚未实现。
  • FontSize 属性定义字体大小。此属性是可选的。该属性的语法是十进制值。位图字体 (与矢量字体相对) 不支持任何字体大小。如果指定了任何不受支持的字体大小,其字体大小将回退到最近支持的字体大小。
  • FontWeight 属性定义字体粗细。此属性是可选的。该属性的语法是任何 System.Windows.FontWeight 值的字符串表示。典型值包括 LightRegularBold。回退值为 Regular。请注意,Windows® 字体通常使用 Normal 值表示字体粗细,而 X11 字体通常使用 Regular 值表示等效的字体粗细。大多数默认字体系列仅支持少数字体粗细,并且某些字体粗细不被任何默认字体系列支持。

ListView 将 (除已知功能外) 由以下方式定义:

  • ItemSource 属性定义用于创建显示项的数据源。此属性是可选的。该属性的语法可以是 {x:Static <资源名称>} 用于静态资源,或者 {Binding <路径>, ElementName=<控件名称>, Mode=<模式>} 用于动态资源。数据源必须实现 System.Collections.IEnumerable。动态数据源还应实现 INotifyPropertyChanged。目前 Mode 尚未实现。

Slider 将由以下方式定义:

  • Name 属性定义类实例的名称,可用于唯一标识该类实例。如果此类实例需要通过 C# 代码访问,则此属性是推荐的或必需的。
  • Grid.Column 属性定义控件在网格内应该放置的零基列索引。默认值为 0。对于网格的子元素,此属性是推荐的,但对于放置在非第 0 列的控件,它是必需的。索引不得超过可用的网格列数。
  • Grid.Row 属性定义控件在网格内应该放置的零基行索引。默认值为 0。对于网格的子元素,此属性是推荐的,但对于放置在非第 0 行的控件,它是必需的。索引不得超过可用的网格行数。
  • Orientation 属性定义方向。此属性是可选的。默认值为水平
  • Minimum 属性定义可能的最小值。此属性是可选的。默认值为0.0F
  • Maximum 属性定义可能的最大值。此属性是可选的。默认值为100.0F
  • Value 属性定义当前选定的值。此属性是可选的。默认值为Minimum
  • SmallChange 属性当前未实现。
  • LargeChange 属性当前未实现。

TextBlock (类似于 Label,但支持自动换行) 将由以下方式定义:

  • Name 属性定义类实例的名称,可用于唯一标识该类实例。如果此类实例需要通过 C# 代码访问,则此属性是推荐的或必需的。
  • Grid.Column 属性定义控件在网格内应该放置的零基列索引。默认值为 0。对于网格的子元素,此属性是推荐的,但对于放置在非第 0 列的控件,它是必需的。索引不得超过可用的网格列数。
  • Grid.Row 属性定义控件在网格内应该放置的零基行索引。默认值为 0。对于网格的子元素,此属性是推荐的,但对于放置在非第 0 行的控件,它是必需的。索引不得超过可用的网格行数。
  • Text 属性定义要显示的文本。此属性是可选的。默认值为空字符串。
  • FontFamily 属性定义字体系列名称。此属性是可选的。该属性的语法是<字体系列名称>,例如 Arial,或者 <字体铸造厂名称>-<字体系列名称>,例如 Adobe-Utopia。第一种语法完全兼容 Microsoft®,第二种语法是 X11 字体规范所必需的。
  • FontWeight 属性定义字体粗细。此属性是可选的。该属性的语法是任何 System.Windows.FontWeight 值的字符串表示。典型值包括 LightRegularBold。回退值为 Regular。请注意,Windows® 字体通常使用 Normal 值表示字体粗细,而 X11 字体通常使用 Regular 值表示等效的字体粗细。大多数默认字体系列仅支持少数字体粗细,并且某些字体粗细不被任何默认字体系列支持。
  • FontStretch 属性定义字体伸展度。此属性是可选的。该属性的语法是任何 System.Windows.FontStretch 值的字符串表示。典型值包括 SemiCondensedMediumSemiExpanded。回退值为 Medium。大多数默认字体系列仅支持少数字体伸展度,并且某些字体伸展度不被任何默认字体系列支持。
  • FontStyle 属性定义字体样式。此属性是可选的。该属性的语法是任何 System.Windows.FontStyle 值的字符串表示。典型值包括 NormalItalicOblique。回退值为 Normal。并非所有默认字体系列都支持每种字体样式。
  • FontSize 属性定义字体大小。此属性是可选的。该属性的语法是十进制值。位图字体 (与矢量字体相对) 不支持任何字体大小。如果指定了任何不受支持的字体大小,其字体大小将回退到最近支持的字体大小。

代码隐藏 (MainView.xaml.cs)

主视图对应的 C# 代码文件是 MainView.xaml.cs。它处于初始状态,因此几乎是空的。

using System;

using X11;
using Xrw;
using XrwXAML;

namespace XamlFontApp
{
    /// <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, IView
    {
        
        /// <summary>The default constructor.</summary>
        public MainView ()
            : base (-1, -1)
        {
            InitializeComponent ();
            // Will be called after construction by generated code!
        }
    }
}

主视图模型文件上下文

MainWindowViewModel.cs 文件保持初始状态。ViewModel 未向应用程序提供任何功能。

主模型文件上下文

MainModel.cs 文件保持初始状态。Model 未向应用程序提供任何功能。

关注点

无需一行代码即可创建如此多的功能,这真是令人惊叹!(并且完全兼容 Microsoft®)。

前三篇关于“为 X11 编写 XAML 应用程序”的文章已经展示了如何编写可以完全移植到 Windows® 和 X11 的单视图应用程序。下一步应该是证明这一点可以用于多视图应用程序。

自2015年2月2日起,文章为 X11 编写 XAML 计算器应用程序延续了 XAML 主题。

历史

本文的第一个版本发布于 2014 年 11 月 22 日。
第一个审阅版本发布于 2015 年 2 月 19 日。
第二个审阅版本发布于 2015 年 2 月 19 日。

© . All rights reserved.