Partial classes are finally available to C++. Sort of. It’s not part of the new C++11 standard, it’s part of the C++/CX language developed by Microsoft for targeting WinRT on Windows 8.

Partial classes mean that you can define a class spanned across several files. Why is this great? Because it allows developers and automatic code generator tools (such as designers) to edit parts of the same class without interfering one with another. WinRT allows C++ developers to write UI in XAML. This could not have been possible without the support for partial classes.

Partial classes:

  • are available only for ref classes; native classes are not supported
  • are introduced with the partial keyword in all definitions but one

Here is an example:

// foo.private.h
#pragma once

partial ref class foo // <- here the partial keyword is used
{
private:
   int _id;
   Platform::String^ _name;
};
// foo.public.h
#pragma once
#include "foo.private.h"

ref class foo // <- partial keyword is not used here
{
public:
   int GetId();
   Platform::String^ GetName();
};
// foo.cpp
#include "pch.h"
#include "foo.public.h"

int foo::GetId() {return _id;}
Platform::String^ foo::GetName {return _name;}

What happens when you add a new page to a C++ Metro style application? The wizard generates three files: a XAML file and a header and cpp file as the code behind. Let's say the page is called MainPage. In this case the three files are MainPage.xaml (code below is a dummy example), MainPage.xaml.h and MainPage.xaml.cpp.

<UserControl x:Class="DemoApp.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    d:DesignHeight="768" d:DesignWidth="1366">

    <StackPanel Name="firstPanel">
        <Button Name="firstButon" />
    </StackPanel>

</UserControl>
//
// MainPage.xaml.h
// Declaration of the MainPage.xaml class.
//

#pragma once

#include "pch.h"
#include "MainPage.g.h"

namespace DemoApp
{
   public ref class MainPage
   {
      public:
         MainPage();
         ~MainPage();
   };
}
//
// MainPage.xaml.cpp
// Implementation of the MainPage.xaml class.
//

#include "pch.h"
#include "MainPage.xaml.h"

using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace DemoApp;

MainPage::MainPage()
{
   InitializeComponent();
}

MainPage::~MainPage()
{
}

You can notice that the objects firstPanel and firstButton are not defined in the header for MainPage and second, MainPage.xaml.h includes MainPage.g.h. So what is this? This is a designer generated file, which together with MainPage.g.cpp completes the definition of the MainPage ref class. These files are not generated until you start a build. After you do that you can find them in the output folder (Debug or Release for instance). This is how they look:

#pragma once
//------------------------------------------------------------------------------
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
//------------------------------------------------------------------------------

namespace Windows {
    namespace UI {
        namespace Xaml {
            namespace Controls {
                ref class StackPanel;
                ref class Button;
            }
        }
    }
}

namespace DemoApp
{
    partial ref class MainPage : public Windows::UI::Xaml::Controls::UserControl,
                                                     public Windows::UI::Xaml::Markup::IComponentConnector
    {
    public:
        void InitializeComponent();
        void Connect(int connectionId, Platform::Object^ pTarget);

    private:
        Windows::UI::Xaml::Controls::StackPanel^ firstPanel;
        Windows::UI::Xaml::Controls::Button^ firstButon;
    };
}
//------------------------------------------------------------------------------
//     This code was generated by a tool.
//
//     Changes to this file may cause incorrect behavior and will be lost if
//     the code is regenerated.
//------------------------------------------------------------------------------
#include "pch.h"

#include "MainPage.xaml.h"

using namespace Windows::Foundation;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Markup;
using namespace MyDemoApplication1;

void MainPage::InitializeComponent()
{
    // Call LoadComponent on ms-resource://DemoApp/Files/MainPage.xaml
    Windows::UI::Xaml::Application::LoadComponent(this, ref new Windows::Foundation::Uri("ms-resource://DemoApp/Files/MainPage.xaml"));

    // Get the StackPanel named 'firstPanel'
    firstPanel = safe_cast<Windows::UI::Xaml::Controls::StackPanel^>(static_cast<IFrameworkElement^>(this)->FindName("firstPanel"));

    // Get the Button named 'firstButon'
    firstButon = safe_cast<Windows::UI::Xaml::Controls::Button^>(static_cast<IFrameworkElement^>(this)->FindName("firstButon"));

}

void MainPage::Connect(int connectionId, Platform::Object^ pTarget)
{
}

The following image illustrates the grouping of these files:

MainPage.xaml is a XAML files, which can be edited both by the designer or manually by the developer (basically with the designer is still the developer that models the UI). The other files are C++/CX files. MainPage.xaml.h and MainPage.xaml.cpp are the files the developer writes, while MainPage.g.h and MainPage.g.cpp are edited by the designer. Do not modify the code in these files, because you could either mess up the designer, or all your changes would get lost when the file is regenerated.

, , , , , , Hits for this post: 3933 .

When you create a WPF application, the start-up window is by default one from the same project (by default called Window1.xaml).

< Application x:Class="WpfApplication1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="Window1.xaml" >
    < Application.Resources >

    < /Application.Resources >
< /Application >

But what if you want to use a window from another project (class library)? The pack URI scheme, used by WPF, allows you to identify and load files from:

  • the current assembly
  • a referenced assembly
  • a location relative to an assembly
  • the site of origin for the application

The format of the pack URI is pack://authority/path. The authority identifies the type of package and the path the location of a part inside a package. There are two authorities supported by WPF:

  • application:/// identifies application data files (known at compile time)
  • siteoforigin:/// identifies site of origin files

To use resource files from a referenced assembly you need to use the application:/// authority, and the path must have the form AssemblyShortName[;Version][;PublicKey];component/Path. Version and PublicKey are optional.

Let’s say you want to use a XAML called SampleWindow.xaml from a referenced assembly called WpfDemoLib. The App.xaml file should look like this:

< Application x:Class="WpfApplication1.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="pack://application:,,,/WpfDemoLib;component/SampleWindow.xaml" >
    < Application.Resources >

    < /Application.Resources >
< /Application >

You can learn more about pack URIs in WPF from MSDN.

, , , , Hits for this post: 12981 .

A WPF TabControl contains multiple items (TabItem), just like any tab control, and adding new tabs is quite easy. The following example shows a tab control with two tab items.

Empty tab with two items


    
		
			
			
		
	

However, when you try adding child controls to a TabItem you’ll notice that you can actually add one single child. The following XAML code yields an error.


    
	
		
			
			
		
		
	
   

error MC3089: The object ‘TabItem’ already has a child and cannot add ‘TextBox’. ‘TabItem’ can accept only one child. Line 9 Position 6.
The solution however is simple: use a grid or panel (Grid, UniformGrid, StackPanel or WrapPanel) to host multiple items. In the example bellow a Grid control was used to host the label and textbox.


    
	
		
			
				
				
			
		
		
	
   

The result can be seen in the following image:

Multiple items in a grid in a tab item

You can create all that from code. The equivalent in C# is the following:

public Window1()
{
        InitializeComponent();

        // create a new tab control
        TabControl tab = new TabControl();

        // create tab items and add them to the tab control
        TabItem item1 = new TabItem();
        item1.Header = "First";
        tab.Items.Add(item1);

        TabItem item2 = new TabItem();
        item2.Header = "Second";
        tab.Items.Add(item2);

        // create a new grid to host other controls
        Grid grid1 = new Grid();

        // create a label and add it to the grid childred
        Label label1 = new Label();
        label1.Margin = new Thickness(10, 10, 0, 0);
        label1.VerticalAlignment = VerticalAlignment.Top;
        label1.HorizontalAlignment = HorizontalAlignment.Left;
        label1.Width = 66;
        label1.Content = "Name";
        grid1.Children.Add(label1);

        // create a textbox and add it to the grid childred
        TextBox textBox1 = new TextBox();
        textBox1.Margin = new Thickness(80, 10, 10, 0);
        textBox1.VerticalAlignment = VerticalAlignment.Top;
        grid1.Children.Add(textBox1);

        // set the grid as the content of a tab item
        item1.Content = grid1;

        // add the tab control to the main grid of the window
        masterGrid.Children.Add(tab);
}

where masterGrid is the main grid in the window:

public partial class Window1 :
     System.Windows.Window, System.Windows.Markup.IComponentConnector {

     internal System.Windows.Controls.Grid masterGrid;



Hits for this post: 19527 .