Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / X11

Writing a XAML application for X11 with UserControls

4.43/5 (3 votes)
16 Aug 2015CPOL11 min read 18.1K   292  
Currently none of the big Linux/Unix (X11) GUI application frameworks (GTK+, KDE) support XAML based application development. The Moonlight project (including XAML support) was abandoned on May 29, 2012. This article reviews a XAML based application utilizing WPF UserControls.

Introduction

This article is a case study, how to write a MVVM (Model View ViewModel) design pattern based X11 application (utilizing WPF UserControls) with XAML using the Roma Widget Set (Xrw). The Roma Widget Set is a zero dependency GUI application framework for X11 (it requires only assemblies of the free Mono standard installation and libraries of the free X11 distribution; it doesn't particularly require GNOME, KDE, cairo, pango or commercial libraries) and is implemented entirely in C#.

This article continues the works Writing a XAML dialog application for X11, Writing a XAML ribbon application for X11, Writing a XAML application for X11 with massive data binding and zero code, Writing a XAML calculator application for X11 and Writing a XAML application with geometry objects (shapes) for X11. As far as i know, this (utilizing the Xrw) is the first attempt to use XAML for X11 application development after the abandonment of Moonlight.

Neither the Roma Widget Set nor the XAML implementation are complete. This sample application is intended as yet another 'proof of concept' and checks out if and how it is possible to create MVVM design pattern based X11 application with XAML.

Since this sixth attempt to use XAML for a X11 application development has been successful, further articles about XAML using the Roma Widget Set on X11 will follow certenly.

Background

The Motivation and the general Concept to use XAML for X11 application development are already explained in the Writing a XAML dialog application for X11 article.

The XAML interpreter has been reworked almost completely. The XAML preprocessor takes care for project sub-folders now. Both changes made working with WPF UserControls more comfortable.

Focus

Since the previous fife articles "Writing XAML ..." already demonstrated several MVVM techniques, this article shall demonstrate that with XAML for X11

  • UserControls can be created and used.

Using the code

The sample application was written with Mono Develop 2.4.1 for Mono 2.8.1 on OPEN SUSE 11.3 Linux 32 bit EN and GNOME desktop. Neither the port to any older nor to any newer version should be a problem. The sample application's solution consists of two projects (the complete sources are provided for download):

  • XamlUserControls contains the source code of the sample application.
  • XamlPreprocessor contains the source code of the XAML preprocessor.

The sample application is also tested with Mono Develop 3.0.6 for Mono 3.0.4 on OPEN SUSE 12.3 Linux 64 bit DE and GNOME desktop, IceWM, TWM und Xfce.

The only difference between the 32 bit and the 64 bit solution is the definition of some X11 specific data types, as already described in the Programming Xlib with Mono develop -Part 1: Low level (proof of concept) article.

The Xlib/X11 window handling is based on the X11Wrapper assembly version 0.9 (a library version 0.9 preview is included in this sample project), that defines the function prototypes, structures and types for Xlib/X11 calls to the libX11.so. This assembly has been developed for the Programming Xlib with Mono Develop - Part 1: Low-level (proof of concept) project and has been advanced during the Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework - Basics project.

The GUI framework is based on the Xrw assembly version 0.9 (a library version 0.9 preview is included in this sample project), that defines the widgets/gadgets and its wrapper classes used within the XAML code (that should be as near to the Microsoft® original as reasonable). This assembly has been developed during the Programming the Roma Widget Set (C# X11) - a zero dependency GUI application framework - Basics project.

Advice: To use the class library documentation shortcut (F1) from MonoDevelop, the "mono-tools" package has to be installed.

The sample application is based on idea and code, taken from the woderful Chess Program in C# by Jacques Fournier. Thank you Jacques Fournier, i will probably transfer the complete application to X11.  This is the reason why namespaces and other things are SrcChess2.

All images show the sample application in the same state: Shown are, from left to right, (below the menu bar and above the status bar)

  • - the empty chessboard user control (displaying a chess board surrounded with field names),
  • - the move viewer user control (displaying the moves done, with some sample output) and
  • - the lost pieces user control (displaying some icons instead the lost chess pieces).

The first image shows the sample application on OPEN SUSE 11.3 Linux 32 bit EN and GNOME desktop.

Image 1

The second image shows the sample application on OPEN SUSE 12.3 Linux 64 bit DE and Xfce.

Image 2

The third image shows the sample application on Windows® 8.1 64 Bit Edition.

Image 3

The application window utilizes the System.Windows.Controls.DockPanel as it's root layout manager. A simple menu bar with the one-level menus File and ? is docked to the top and a status bar is docked to the bottom; both use the complete available width. One System.Windows.Controls.Grid, docked to fill, organizes the three user controls to demonstrate. They are:

  1. The ChessBoardControl user control, defined within ChessBoardControl.xaml, that displays an empty chess board surrounded with a border that displays the field names. Chess board and border are realized by several StackPanel, UniformGrid and Grid layouter controls in a manner, that enables the chessboard to resize according the current window size. The chess board user control is embedded into the application by a Viewbox, that stretches equally into both directions. This ensures that the chess board appears always quadratic, no matter which specific geometry the application window has.
  2. The MoveViewer user control, defined within MoveViewer.xaml, that displays a list of the current matches' already done moves. This list uses data binding to the MoveListData class.
  3. And the LostPiecesControl user control, defined within LostPiecesControl.xaml, that displays currently some icons instead the current matches' lost chess pieces for demonstration. This control is used twice, for the white and for the black player. It offers space for 4 x 4 images to be able to hold all 16 chess pieces one player owns.

There is no functional difference between the X11 and Windows 8.1 versions of the sample application, they share the same code entirely.

Walk through

The Project setup, Application file context (except the theme) and Preporocessor code generation steps are exactly the same as in Writing a XAML dialog application for X11. Please refer to this article, if a new solution shall be created from scratch.

Even it the X11 and Windows 8.1 versions of the sample application share the same code entirely, i want to point out some differences between the X11 and Windows 8.1 versions of the C# project.

While Visual Studio integrates a procedure that compiles the XAML files on the fly to BAML files (the binary equivalent to realize a syntax check, that hurries ahead, and to shorten initialization time during application start) and interprets the BAML file during application start to bind the controls and the native C# code, MonoDevelop just provides to run user defined tasks at certain points in time.

Image 4

Therefore the MonoDevelop project pre-compiles the XAML files before the application compilation process to native C# code (using the XamlPreprocessor that is part of the project and some Xrw class ectensions).

This requires some different source file properties for the MonoDevelop project compared to the Visual Studio project.

While the MonoDevelop

  • treats all XAML files through the pre-compilation user task,
  • takes no action (even no compilation) during the build process and
  • must include the resulting C# files into the application build process (after first pre-compilation of a *.xaml file, the resulting *.generated.cs file must be included into the C# project manually),

Image 5

the Visual Studio project

  • treats the XAML files as a Page during build process by an external compiler call (MSBuild: Compile),

Image 6

  • compiles the code behind files like any C# file during the build process and

Image 7

  • requires XAML file and associated code behind file to be structured hierarchically.

Image 8

Main view file context

The XAML (MainView.xaml)

First the XAML file with references to the four user controls (ChessBoardControl , MoveViewer and 2 x MoveViewer).

XML
<Window         x:Class="SrcChess2.MainView"
                xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:src="clr-namespace:SrcChess2"
                xmlns:my="clr-namespace:SrcChess2"
                Name="SrcChess" Title="SrcChess for WPF"
                Width="650" Height="450" Icon="XrwIcon16.bmp"
                Background="SkyBlue">
    <!-- Idea based on: "Chess Program in C#" by Jacques Fournier on
         http://www.codeproject.com/Articles/36112/Chess-Program-in-C -->
    <Window.Resources>
        <src:MainWindowViewModel x:Key="MainViewModel" />
        <!-- MainWindowViewModel : ViewModelCore<T>.ctr()
             automatically registeres itself as the initial Window.DataContext. -->
    </Window.Resources>
    <DockPanel Name="m_dockPanelMain" DataContext="{StaticResource MainViewModel}">
        <Menu      Name="MainMenu"         DockPanel.Dock="Top" >
            <MenuItem Name="MenuItemFile"  Header="_File ">
                <MenuItem Name="MenuItemFileCopy"   Header="Copy">
                    <MenuItem.Icon>
                        <Image Source="Images/copy16.bmp"/>
                    </MenuItem.Icon>
                </MenuItem>
                <MenuItem Name="MenuItemFilePaste"  Header="Paste">
                    <MenuItem.Icon>
                        <Image Source="Images/paste16.bmp"/>
                    </MenuItem.Icon>
                </MenuItem>
                <Separator/>
                <MenuItem Name="MenuItemFileEdit"   Header="Exit"   Click="MenuItemFileExit_Click">
                    <MenuItem.Icon>
                        <Image Source="Images/exit16.bmp"/>
                    </MenuItem.Icon>
                </MenuItem>
            </MenuItem>
            <MenuItem Name="MenuItemQmark" Header="_?">
                <MenuItem Name="MenuItemQmarkHelp"  Header="Help"   Click="MenuItemQmarkHelp_Click">
                    <MenuItem.Icon>
                        <Image Source="Images/quest16.bmp"/>
                    </MenuItem.Icon>
                </MenuItem>
                <MenuItem Name="MenuItemQmarkAbout" Header="About"  Click="MenuItemQmarkAbout_Click">
                    <MenuItem.Icon>
                        <Image Source="Images/info16.bmp"/>
                    </MenuItem.Icon>
                </MenuItem>
            </MenuItem>
        </Menu>
        
        <StatusBar Name="m_statusBar" DockPanel.Dock="Bottom">
            <StatusBarItem Name="m_statusLabelSearchMode" Content="Alpha-Beta (6 Ply)" />
            <Separator />
            <StatusBarItem Name="m_statusLabelMove" Content="Move" />
            <Separator />
            <StatusBarItem Name="m_statusLabelPermutation" Content="Permutation" />
        </StatusBar>
        
        <Grid Name="m_chessBoardAndMoveViewer">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="5*"></ColumnDefinition>
                <ColumnDefinition Width="Auto"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>

            <Viewbox Name="m_viewboxChessBoardControl" Grid.Column="0" Grid.Row="0" >
                <my:LocalChessBoardControl x:Name="m_chessCtl" LiteCellColor="Moccasin" />
            </Viewbox>
            
            <my:MoveViewer x:Name="m_moveViewer" Grid.Column="1" Grid.Row="0"
                           Margin="0,10" Width="210"></my:MoveViewer>
            
            <StackPanel Name="m_stackPanelLostPieces" Grid.Column="2" VerticalAlignment="Center">
                <my:LostPiecesControl x:Name="m_lostPieceBlack" Margin="4,2,4,4"
                                      BorderBrush="LightGray" BorderThickness="1" />
                <my:LostPiecesControl x:Name="m_lostPieceWhite" Margin="4,4,4,0"
                                      BorderBrush="LightGray" BorderThickness="1" />
            </StackPanel>
        </Grid>
    </DockPanel>
</Window>

The complete XAML code is fully Microsoft® compatible.

Compared to Writing a XAML application with geometry objects (shapes) for X11 and previous articles, only the enhancments and differences will be discussed.

The StatusBar will be defined by:

  • The Name attribute defines the class instance name, that can be used to identify the class instance uniquely. This attribute is recommended, or mandatory if this class instance has to be accessible through C# code.

The StatusBar supports the children StatusBarItem and Separator.

The StatusBarItem will be defined by:

  • The Name attribute defines the class instance name, that can be used to identify the class instance uniquely. This attribute is recommended, or mandatory if this class instance has to be accessible through C# code.
  • The Content attribute defines the information to display. This attribute is optional. The syntax of the attribute currently supports string only.

The Separator doesn't support any attributes. The current implementation doesn't create a separate control, but instead it investigates the lastStatusBarItem and sets it's Xrw frame type to TFrameType.VertRigtDelimiter.

The ViewBox will be defined by:

  • The Name attribute defines the class instance name, that can be used to identify the class instance uniquely. This attribute is recommended, or mandatory if this class instance has to be accessible through C# code.

The my:LocalChessBoardControl, my:MoveViewer and my:LostPiecesControl nodes refer to the appropriate user controls.

Limitations of the XAML syntax

X11/Xrw implementation:

  • The StatusBarItem's Content attribute is limited to string.
  • The Separator is not a separate control.

The code behind (MainView.xaml.cs)

The corresponding C# code file of the main view is MainView.xaml.cs. and it remains in initial state. There is no additional functionality provided to the MainView.

Main view model file context

The MainWindowViewModel.cs file remains in initial state. There is no additional functionality provided to the application by the ViewModel.

Main model file context

The MainModel.cs file remains in initial state. There is no additional functionality provided to the application by the Model.

Most simple UserControl - LostPiecesControl

The XAML (LostPiecesControl.xaml)

The XAML file of the user control is:

XML
<UserControl x:Class="SrcChess2.LostPiecesControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008">
    <Viewbox Stretch="UniformToFill">
        <Border Name="MainBorder">
            <UniformGrid Name="CellContainer" Rows="4" Columns="4" MinWidth="0" MinHeight="0">
            </UniformGrid>
        </Border>
    </Viewbox>
</UserControl>

The format of a UserControl's XML file is very similar to the format of a standard Windows XAML file. There is nothing new to the XrwXAML controls, used for this user control.

The code behind (LostPiecesControl.xaml.cs)

The corresponding C# code file of the user control is LostPiecesControl.xaml.cs. The class constructor calls InitializeComponent() (just like a Windows control) and FillCellContainer(), that contains the code to create some icons (instead of the lost chess pieces) for demonstration.

C#
/// <summary>Interaction logic for LostPiecesControl.xaml.</summary>
public partial class LostPiecesControl : UserControl
{
    public LostPiecesControl()
    {
        InitializeComponent();

        FillCellContainer();
    }

    public void FillCellContainer()
    {
        System.Windows.Media.Imaging.BitmapImage imageSource  = null;
        System.Windows.Controls.Image             imageControl = null;

        for (int counter = 0; counter < 5; counter++)
        {
            string sourceImagePath;
            sourceImagePath = System.IO.Path.GetDirectoryName(
                                  System.Reflection.Assembly.GetExecutingAssembly().Location);
            if (counter == 0)
                sourceImagePath += System.IO.Path.DirectorySeparatorChar + "Images" +
                                   System.IO.Path.DirectorySeparatorChar + "copy16.bmp";
            else if (counter == 1)
                sourceImagePath += System.IO.Path.DirectorySeparatorChar + "Images" +
                                   System.IO.Path.DirectorySeparatorChar + "exit16.bmp";
            else if (counter == 2)
                sourceImagePath += System.IO.Path.DirectorySeparatorChar + "Images" +
                                   System.IO.Path.DirectorySeparatorChar + "info16.bmp";
            else if (counter == 3)
                sourceImagePath += System.IO.Path.DirectorySeparatorChar + "Images" +
                                   System.IO.Path.DirectorySeparatorChar + "paste16.bmp";
            else
                sourceImagePath += System.IO.Path.DirectorySeparatorChar + "Images" +
                                   System.IO.Path.DirectorySeparatorChar + "quest16.bmp";

            imageSource = new System.Windows.Media.Imaging.BitmapImage(new Uri(sourceImagePath));

            imageControl = new System.Windows.Controls.Image();
            imageControl.Source = imageSource;
            CellContainer.Children.Add(imageControl);
        }
    }
}

Less simple UserControl - MoveViewer

The XAML (MoveViewer.xaml)

The XAML file of the user control is:

XML
<UserControl x:Class="SrcChess2.MoveViewer"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:my="clr-namespace:SrcChess2">
    <UserControl.Resources>
        <my:MoveItemList x:Key ="MoveListData" />
    </UserControl.Resources>
    <Grid Name="gridMoveList" >
        <ListView Name="listViewMoveList" HorizontalAlignment="Stretch" VerticalAlignment="Top"
                  SelectionMode="Single"
                  ItemsSource="{Binding Source={StaticResource MoveListData}}" IsEnabled="True">
          <ListView.View>
            <GridView>
                <GridView.Columns>
                    <GridViewColumn Header="Step" DisplayMemberBinding="{Binding Path=Step}" Width="60" />
                    <GridViewColumn Header="Who"  DisplayMemberBinding="{Binding Path=Who}"  Width="60" />
                    <GridViewColumn Header="Move" DisplayMemberBinding="{Binding Path=Move}" Width="60" />
                </GridView.Columns>
            </GridView>
          </ListView.View>
        </ListView>
    </Grid>
</UserControl>

This UserControl's XML file contains a Resource just lice a standard Windows XAML file can do. There is nothing new to the XrwXAML controls, used for this user control.

The code behind (MoveViewer.xaml.cs)

The corresponding C# code file of the user control is LostPiecesControl.xaml.cs. The class constructor calls InitializeComponent() (just like a Windows control).

The file contains as well a minimalistic implementation if the MoveItemList class, that is referenced by the Resource node of the XAML file. This class provides the list of the current matches' already done moves and is initialized with four sample moves for demonstration.

C#
/// <summary>Move Item.</summary>
public class MoveItem
{
    /// <summary>
    /// Class Ctor
    /// </summary>
    /// <param name="step">     Move step</param>
    /// <param name="who">      Who did the move</param>
    /// <param name="move">     Move</param>
    public MoveItem(string step, string who, string move) { Step = step; Who = who; Move = move; }
    /// <summary>Step</summary>
    public string Step { get; set; }
    /// <summary>Who did the move</summary>
    public string Who { get; set; }
    /// <summary>Move</summary>
    public string Move { get; set; }
}

/// <summary>List of moves</summary>
public class MoveItemList : ObservableCollection<MoveItem>
{
    public MoveItemList()
    {
        this.Add(new MoveItem("1a", "White pawn", "D2-D4"));
        this.Add(new MoveItem("1b", "Black pawn", "D7-D5"));
        this.Add(new MoveItem("2a", "White knight", "B1-C3"));
        this.Add(new MoveItem("2b", "Black knight", "B8-C6"));
    }
}

/// <summary>User interface displaying the list of moves.</summary>
public partial class MoveViewer : UserControl
{

    /// <summary>Initialize a new instance of the SrcChess2.MoveViewer class.</summary>
    public MoveViewer()
    {
        InitializeComponent();
    }

}

Last UserControl - ChessBoardControl

The XAML (ChessBoardControl.xaml)

The XAML file of the user control is:

C#
<UserControl x:Class="SrcChess2.ChessBoardControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:my="clr-namespace:SrcChess2">
    <StackPanel Name="m_stackPanelOuter">
        <StackPanel Name="m_stackPanelTop" Height="20" Orientation="Horizontal">
            <Border Name="m_placeHolderLeftTop" Width="20" />
            <UniformGrid Name="m_uniformGridColumnsTop"    Rows="1" Columns="8" Height="16">
                <Label Content="a" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="b" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="c" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="d" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="e" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="f" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="g" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="h" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
            </UniformGrid>
            <Border Name="m_placeHolderRightTop" Width="20" />
        </StackPanel>
        <StackPanel Name="m_stackPanelCenter" Orientation="Horizontal">
            <UniformGrid Name="m_uniformGridRowsLeft" Rows="8" Columns="1" Width="16" >
                <Label Content="8" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="7" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="6" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="5" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="4" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="3" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="2" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="1" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
            </UniformGrid>
            <Grid Name="m_gridCellContainer" MinWidth="100" MinHeight="100">
                <Grid.RowDefinitions>
                    <RowDefinition Height="*" SharedSizeGroup="A" />
                    <RowDefinition Height="*" SharedSizeGroup="A" />
                    <RowDefinition Height="*" SharedSizeGroup="A" />
                    <RowDefinition Height="*" SharedSizeGroup="A" />
                    <RowDefinition Height="*" SharedSizeGroup="A" />
                    <RowDefinition Height="*" SharedSizeGroup="A" />
                    <RowDefinition Height="*" SharedSizeGroup="A" />
                    <RowDefinition Height="*" SharedSizeGroup="A" />
                </Grid.RowDefinitions>
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="*" SharedSizeGroup="A" />
                    <ColumnDefinition Width="*" SharedSizeGroup="A" />
                    <ColumnDefinition Width="*" SharedSizeGroup="A" />
                    <ColumnDefinition Width="*" SharedSizeGroup="A" />
                    <ColumnDefinition Width="*" SharedSizeGroup="A" />
                    <ColumnDefinition Width="*" SharedSizeGroup="A" />
                    <ColumnDefinition Width="*" SharedSizeGroup="A" />
                    <ColumnDefinition Width="*" SharedSizeGroup="A" />
                </Grid.ColumnDefinitions>
            </Grid>
            <UniformGrid Name="m_uniformGridRowsRight" Rows="8" Columns="1" Width="16" >
                <Label Content="8" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="7" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="6" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="5" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="4" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="3" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="2" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="1" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
            </UniformGrid>
        </StackPanel>
        <StackPanel Name="m_stackPanelBottom" Height="20" Orientation="Horizontal">
            <Border Name="m_placeHolderLeftBottom" Width="20" />
            <UniformGrid Name="m_uniformGridColumnsBottom"    Rows="1" Columns="8" Height="16">
                <Label Content="a" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="b" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="c" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="d" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="e" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="f" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="g" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
                <Label Content="h" HorizontalContentAlignment="Center"
                       VerticalContentAlignment="Center" Padding="0" />
            </UniformGrid>
            <Border Name="m_placeHolderRightBottom" Width="20" />
        </StackPanel>
    </StackPanel>
</UserControl>

There is nothing new to the XrwXAML controls, used for this user control.

The code behind (ChessBoardControl.xaml.cs)

The corresponding C# code file of the user control is ChessBoardControl.xaml.cs. The class constructor calls InitializeComponent() (just like a Windows control) and InitCell(), that contains the code to create the 64 chess board cells from 64 Border controls with alternating background color.

The file contains as well a lot of code to provide dependency properties and to define class cproperties, that aren't used currently. Therefore i will concentrate on InitCell().

C#
/// <summary>Chess board for the chess program.</summary>
public partial class ChessBoardControl : UserControl
{

    ...

   
    /// <summary>Initializing constructor.</summary>
    public ChessBoardControl ()
    {
        InitializeComponent();
        //...
        InitCell();
    }

    ...

    /// <summary>
    /// Initialize the cell
    /// </summary>
    private void InitCell()
    {
        int iPos = 36;
        Border border;
        Brush brushDark;
        Brush brushLite;
        
        brushDark = new SolidColorBrush(DarkCellColor);   // m_colorInfo.m_colDarkCase);
        brushLite = new SolidColorBrush(LiteCellColor);   // m_colorInfo.m_colLiteCase);
        for (int y = 0; y < 8; y++)
        {
            for (int x = 0; x < 8; x++)
            {
                border = new Border ();
                border.Name = "Cell" + ("00" + iPos.ToString()).Right (2);
                border.BorderThickness = new Thickness(0);
                border.Background = (((x + y) & 1) == 0) ? brushLite : brushDark;
                border.BorderBrush = border.Background;
                
                m_gridCellContainer.Children.Add(border);
#if WINDOWS
                // Microsoft requires any initial size,
                // big enough to span the grid over the complete free space...
                border.Width = 40;
#else
                // Linux needs to set child constraints.
                m_gridCellContainer.SetChildConstraints (border, "0", x.ToString(), y.ToString(), "0", "0");
#endif
                iPos--;
            }
        }
    }
    
}

The conditional compilation symbol WINDOWS is set for the Windows 8.1 project only. It carves out the currently single one difference between the X11 and Windows 8.1 versions of the sample application.

Points of Interest

This is another XAML application for X11, almost fully compatible with Microsoft®, showing the main advantages of this approach: The 100% compatible GUI definition and the savings of code lines to create the GUI.

The use of user controls can divide complex GUIs into more simple and maintainable peaces amd can be applied for X11 as well.

History

The first version of this article is from 16. July 2015.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)