WPF Control Templates (part 1)

ControlTemplate

Styles and Templates can change the appearance of elements. So what is the difference then?
Templates are far more complex. Styles are mainly adjusting existing properties. You could say that Styles are like Face-Lifting whereas Templates are rather entire face replacements. Elements get new visual trees that can consist of other elements. This is not the case for Styles.

Before we start creating our own templates let’s have a look at the existing standard control templates. Today’s example code reads these Templates from the assembly and prints them in a TextBox.

Take a stroll and get a feeling for them.
Surely this is not for beginners. My advice is to copy, paste and reuse existing professional XAML rather than spending your precious time to figure out every little issue yourself. And today’s source code aims at exactly that approach.

<Application x:Class="WpfTemplates.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             ShutdownMode="OnMainWindowClose"
             StartupUri="MainWindow.xaml">
    <Application.Resources>
         
    </Application.Resources>
</Application>



<Window x:Class="WpfTemplates.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="Window_Loaded"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel LastChildFill="True">
        <ListBox DockPanel.Dock="Left" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" MinWidth="100" />
        <Grid DockPanel.Dock="Right" Name="dummyGrid" Width="0" />
        <TextBox DockPanel.Dock="Left" Text="{Binding XAML}" TextWrapping="NoWrap" AcceptsReturn="True" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto" FontFamily="Courier New" />
    </DockPanel>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Markup;
using System.Xml;

namespace WpfTemplates {
  public partial class MainWindow : Window {

    private class Data {
      public Type Type { get; set; }
      public string XAML { get; set; }

      public Data(Type xType) { this.Type = xType; XAML = "#N/A"; }
      public override string ToString() { return Type.Name; }
    } // class

    public MainWindow() {
      InitializeComponent();
    } //

    private void Window_Loaded(object sender, RoutedEventArgs e) {
      List<Data> lData = new List<Data>();

      Assembly lAssembly = Assembly.GetAssembly(typeof(Control));
      Type lControlType = typeof(Control);
      List<Data> lTypes = (from t in lAssembly.GetTypes().AsParallel()
                           where t.IsSubclassOf(lControlType) && t.IsPublic && !t.IsAbstract
                           orderby t.Name ascending
                           select new Data(t)).ToList();

      InsertXaml(lTypes);
      DataContext = lTypes;
    } //

    private void InsertXaml(List<Data> xTypes) {
      XmlWriterSettings lXmlWriterSettings = new XmlWriterSettings();
      lXmlWriterSettings.Indent = true;
      StringBuilder lStringBuilder = new StringBuilder(); // for output      

      foreach (Data lData in xTypes) {
        try {
          ConstructorInfo lConstructorInfo = lData.Type.GetConstructor(System.Type.EmptyTypes);
          if (lConstructorInfo == null) {
            lData.XAML = lData.Type.Name + " control cannot be instantiated.";
            continue;
          }
          Control lControl = lConstructorInfo.Invoke(null) as Control;  // create an instance
          lControl.Visibility = System.Windows.Visibility.Collapsed;
          bool lIsNullTemplate = (lControl.Template == null);          
          if (lIsNullTemplate) dummyGrid.Children.Add(lControl); // add a collapsed (invisible) control to get access to the template
          ControlTemplate lControlTemplate = lControl.Template; // now not null anymore
          using (XmlWriter lXmlWriter = XmlWriter.Create(lStringBuilder, lXmlWriterSettings)) { // will write to StringBuilder
            XamlWriter.Save(lControlTemplate, lXmlWriter);
            lData.XAML = lStringBuilder.ToString();
          }
          lStringBuilder.Clear();
          if (lIsNullTemplate) dummyGrid.Children.Remove(lControl);
        }
        catch (Exception ex) {
          lData.XAML = lData.Type.Name + " control cannot be added to the grid.\n\nException message:\n" + ex.Message;
        }
      }
    } //

  } // class
} // namespace

About Bastian M.K. Ohta

Happiness only real when shared.

Posted on April 22, 2014, in Advanced, Professional, WPF and tagged , , , , , , . Bookmark the permalink. 1 Comment.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: