Standard WPF/Window applications
XAML Application Basics:
Learn XAML
If you’ve seen “Avalon” demos, then you know that it is often developed with using a specialized form of XML called XAML.
It is possible to write “Avalon” to the bare metal using code (C#, VB, or your favorite CLS-Compliant-Language of choice), however the designers of the Avalon libraries have optimized the “feel” of their APIs for XAML – sometimes this is just shortened to the word “markup”. Charles Petzold has an interesting discussion here about when to use what.
Some XAML you gotta know
<!-- Window1.xaml -->
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="WindowsApplication1.Window1"
Title="Main Window">
What is xmlns?
Definition from W3C:
XML namespaces provide a simple method for qualifying element and attribute names used in Extensible Markup Language documents by associating them with namespaces identified by URI references.
By bringing in custom xml namespaces, we essentially bring in another set of “valid” XML element types and attribute names.
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
This pulls in the XML schema for the Windows Presentation Foundation itself. By setting this as the default XML namespace,
we can just create <Button> without prepending it with anything silly like
<wpf:Button>.
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
This brings in XAML keywords, markup extensions (the funny stuff you’ll sometimes see in curly braces). Interesting x: stuff includes
“x:Key” for setting keys in a resource dictionary
“x:Static” for fetching statics off a CLR class
“x:Class” for associating a codebehind
“x:Type” for specifying a type
“x:Null” for setting something to null in XAML
x:Class="WindowsApplication1.Window1"
This helps the XAML compiler to find the associated code-behind – in this case it would look for WindowsApplication1.Window1 as its codebehind file.
Title="Main Window"
Finally an easy one: this one sets the title for the window to say “Main Window”.
Bringing in your own objects to the XAML party
It is possible to create any CLR type within XAML. You just need to learn the equivalent of the “using” statement in XAML.
<<!-- Window1.xaml -->
<Window x : Class="WindowsApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WindowsApplication1"
>
<lcl:MyButton>Moo </lcl:MyButton>
</Window>
// Window1.xaml.cs
namespace WindowsApplication1 {
public class MyButton : System.Windows.Controls.Button {
}
}
Note that the use of “lcl” is a matter of choice – it’s what you’ll use to prefix your elements from that namespace. We could have replaced all the “local” strings with “foo” or “WindowsApplication1” and it would have worked.
Bringing in custom objects from another assembly
When you bring in an object from another assembly, you have to specify the particular assembly in the xmlns assignment. As usual, you also have to add a reference to the assembly in your Visual Studio project.
<!-- Window1.xaml -->
<Window x:Class="WindowsApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=System"
>
<ListBox>
<sys:String>One</sys:String>
</ListBox>
</Window>
Talking to Elements Defined in XAML From Code
If you name your elements in your XAML file, you can access them as if they were member variables on the class.
<!-- Window1.xaml -->
<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
>
<Canvas>
<TextBox Name="textBox1"></TextBox>
</Canvas>
</Window>
From code:
// Window1.xaml.cs
textBox1.Text = "Hello World!";
You can either write this code in the constructor, or you can use the “Loaded” event instead.
Option 1: Hooking onto the Loaded event from XAML
<!-- Window1.xaml -->
<Window x:Class="WindowsApplication14.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="WindowsApplication14"
Loaded="OnWindowLoaded"
>
<Canvas>
<TextBox Name="textBox1"></TextBox>
</Canvas>
</Window>
// Window1.xaml.cs
private void OnWindowLoaded(object sender, RoutedEventArgs e) {
textBox1.Text = "Hello World!";
}
Option 2: Hooking onto the Loaded event from code
public Window1() {
InitializeComponent();
this.Loaded += new RoutedEventHandler(OnWindowLoaded);
}
void OnWindowLoaded(object sender, RoutedEventArgs e) {
textBox1.Text = "Hello World!";
}
Application and MyApp.xaml
“Avalon” has three kinds of application styles – a simple Application (Window-based, just like windows forms), a NavigationApplication (page based, just like Microsoft Money or a website), and a DocumentApplication (specialized sub-set of NavigationApplication for displaying content).
An “Avalon” application can either be run in two modes: Express (run from browser) and Installed (behaves like classic Windows applications). Just like Windows Forms, “Avalon” works with ClickOnce for installation.
Files in a simple Application
If you create a new “Windows Application (WPF)” in Visual Studio, you’ll get several files:
• MyApp.xaml
o Application declaration in xaml
• MyApp.xaml.cs or MyApp.xaml.vb, etc
o Application code behind – application startup events and so on
• Window1.xaml
o Window declaration in xaml
• Window1.xaml.cs or Window1.xaml.vb, etc
o Window code behind – event handlers and so on
MyApp.xaml and its codebehind file are most like the Program.cs from a C# Windows Forms application. This is where you’ll put anything that applies to the entire application – typically you may want to associate resources, styles to be shared between all your Windows in your application.
Where is Application.Run?
Believe it or not, “Avalon” has an Application.Run too – to find it we need to talk about what happens when you build XAML.
When you build Avalon takes the .xaml and generates a set of files that are then compiled in to the exe. For
.xaml the following are generated:
<Name>.baml
Binary version of the .xaml file. Compiled into the .exe as a resource
<Name>.g.cs (or .g.vb)
Partial class that is combined with <Name>.xaml.cs (or .vb). Contains initialization code that does the following:
. Loads the baml resource to display the UI
. Wires up event handlers
. Wires up member variables to live objects (Button1 for example)
So the build is a two step process – firstly it generates this stuff, then it compiles and generates an exe.
Peeking at MyApp.g.cs
[STAThread()]
public static int Main(string[] args) {
WindowsApplication22.MyApp app = new WindowsApplication22.MyApp();
app.InitializeComponent();
return app.Run(args);
}
So if Main is in an automatically generated class how do I add stuff to Main?
You can hook the StartingUp event on Application to add custom logic.
<!-- MyApp.XAML -->
<Application x:Class="WindowsApplication22.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
Startup="OnApplicationStartingUp"
>
<Application.Resources>
...
</Application.Resources>
</Application>
// MyApp.xaml.cs
public partial class MyApp : Application {
private void OnApplicationStartingUp(object sender,
StartupEventArgs e) {
if (e.Args.Length == 1 && e.Args[0] == "/?") {
MessageBox.Show("Help!");
}
}
}