WPF Metaclass

From IronPython Cookbook

If you prefer to write an WPF application in a class, this is a metaclass that makes it easy to access controls, somewhat like waddle in XAML_GUI_Events_Example. Look at the code and comments at the bottom to see what it does.

Here's the metaclass code (and let's say you save it as WPFUIElements.py)

import clr
clr.AddReference("PresentationFramework")
clr.AddReference("PresentationCore")

from System.Windows import UIElement, LogicalTreeHelper

class WPFClass(type):
    def __new__(meta,classname,bases,classDict):
        
        def __gettreechildren__(control,classDict):
            for item in LogicalTreeHelper.GetChildren(control):
                if hasattr(item,"Name"):
                    if item.Name:
                        classDict[item.Name] = classDict["_xaml"].FindName(item.Name)
                if isinstance(item, UIElement):
                    classDict = __gettreechildren__(item,classDict)
            return classDict
        
        if "_xaml" in classDict.keys():
            classDict = __gettreechildren__(classDict["_xaml"],classDict)
            return type.__new__(meta,classname,bases,classDict)
        else:
            raise Exception("""Please define a _xaml attribute, example:
class Main(Application):
    __metaclass__ = WPFClass
    _xaml = XamlReader.Load(XmlReader.Create(FileStream("main.xaml",FileMode.Open)))""")

Now here's the xaml (saving it as main.xaml, in the same folder):

<Window
	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"
	x:Name="Window"
	Title="MainWindow"
	Width="640" Height="480" mc:Ignorable="d">
	<Window.Resources>
		<Style TargetType="{x:Type MenuItem}">
			<Setter Property="FontFamily" Value="Trebuchet MS"/>
			<Setter Property="FontSize" Value="13.333"/>
		</Style>
	</Window.Resources>

	<Grid x:Name="LayoutRoot">
		<Menu VerticalAlignment="Top" Height="22">
			<MenuItem x:Name="file_menuitem" Header="File" FontFamily="Trebuchet MS" FontSize="13.333">
				<MenuItem x:Name="new_menuitem" Header="New"/>
				<MenuItem x:Name="open_menuitem" Header="Open"/>
			</MenuItem>
		</Menu>
	</Grid>
</Window>

Now here's the main file, in the same folder as the other two files:

import clr
clr.AddReference("PresentationFramework")
clr.AddReference("PresentationCore")
clr.AddReference("System.Xml")

from System.Windows import Application
from System.Windows.Markup import XamlReader
from System.IO import FileStream, FileMode
from System.Xml import XmlReader

from WPFUIElements import WPFClass

class Main(Application):
    __metaclass__ = WPFClass
    _xaml = XamlReader.Load(XmlReader.Create(FileStream("main.xaml",FileMode.Open)))
    def __init__(self):
        pass
    def run(self):
        self.open_menuitem.Header = "Open File"
        #instead of self._xaml.FindName("open_menuitem").Header = "Open File"
        self.new_menuitem.Header = "New File"
        #instead of self._xaml.FindName("new_menuitem").Header = "New File"
        self.Run(self._xaml)

Main().run()

This is made obsolete in IronPython 2.7A, where there is clr.LoadComponent to do the same thing and more.

TOOLBOX
LANGUAGES