Code Reference A collection of code for my reference (and perhaps other people too)

2Sep/090

GridSplitter style – Add a grip

The grid splitter on WPF is very useful, but not easy to style. I found some code to do this. VERY useful!

Horizontal:

    <LinearGradientBrush StartPoint="0,0" EndPoint="0,1" x:Key="panelBackgroundBrush">
        <LinearGradientBrush.GradientStops>
            <GradientStop Color="#FFE3EFFF" Offset="0" />
            <GradientStop Color="#FFAFD2FF" Offset="1" />
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>

    <Style x:Key="gridSplitterStyle" TargetType="{x:Type GridSplitter}">
        <Setter Property="FrameworkElement.Height" Value="8"/>
        <Setter Property="TextElement.Foreground" Value="#FF204D89" />
        <Setter Property="Border.BorderBrush" Value="#FF6593CF" />
        <Setter Property="Panel.Background" Value="{StaticResource panelBackgroundBrush}" />
        <Setter Property="Border.BorderThickness" Value="0,1,0,0" />
        <Setter Property="UIElement.SnapsToDevicePixels" Value="True" />
        <Setter Property="UIElement.Focusable" Value="False" />
        <Setter Property="Control.Padding" Value="7,7,7,7" />
        <Setter Property="FrameworkElement.Cursor" Value="SizeNS" />
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Border BorderThickness="{TemplateBinding Border.BorderThickness}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}">
                        <Border BorderThickness="1,1,0,0" BorderBrush="{StaticResource panelBackgroundBrush}">
                            <Canvas Width="19" Height="3">
                                <Rectangle Fill="{StaticResource panelBackgroundBrush}" Width="2" Height="2" Canvas.Left="1" Canvas.Top="0" />
                                <Rectangle Fill="{StaticResource panelBackgroundBrush}" Width="2" Height="2" Canvas.Left="5" Canvas.Top="0" />
                                <Rectangle Fill="{StaticResource panelBackgroundBrush}" Width="2" Height="2" Canvas.Left="9" Canvas.Top="0" />
                                <Rectangle Fill="{StaticResource panelBackgroundBrush}" Width="2" Height="2" Canvas.Left="13" Canvas.Top="0" />
                                <Rectangle Fill="{StaticResource panelBackgroundBrush}" Width="2" Height="2" Canvas.Left="17" Canvas.Top="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Left="0" Canvas.Top="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Left="4" Canvas.Top="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Left="8" Canvas.Top="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Left="12" Canvas.Top="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Left="16" Canvas.Top="0" />
                            </Canvas>
                        </Border>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

Vertical:

<LinearGradientBrush StartPoint="0,0" EndPoint="0,1" x:Key="panelBackgroundBrush2">
        <LinearGradientBrush.GradientStops>
            <GradientStop Color="#FFE3EFFF" Offset="0" />
            <GradientStop Color="#FFAFD2FF" Offset="1" />
        </LinearGradientBrush.GradientStops>
    </LinearGradientBrush>

    <Style x:Key="gridSplitterVerticalStyle">
        <Setter Property="FrameworkElement.Height" Value="8"/>
        <Setter Property="TextElement.Foreground" Value="#FF204D89" />
        <Setter Property="Border.BorderBrush" Value="#FF6593CF" />
        <Setter Property="Panel.Background" Value="{StaticResource panelBackgroundBrush2}" />
        <Setter Property="Border.BorderThickness" Value="0,1,0,0" />
        <Setter Property="UIElement.SnapsToDevicePixels" Value="True" />
        <Setter Property="UIElement.Focusable" Value="False" />
        <Setter Property="Control.Padding" Value="7,7,7,7" />
        <Setter Property="FrameworkElement.Cursor" Value="SizeWE" />
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Border BorderThickness="{TemplateBinding Border.BorderThickness}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}">
                        <Border BorderThickness="1,1,0,0" BorderBrush="{StaticResource panelBackgroundBrush2}">
                            <Canvas Width="3" Height="19">
                                <Rectangle Fill="{StaticResource panelBackgroundBrush2}" Width="2" Height="2" Canvas.Top="1" Canvas.Left="0" />
                                <Rectangle Fill="{StaticResource panelBackgroundBrush2}" Width="2" Height="2" Canvas.Top="5" Canvas.Left="0" />
                                <Rectangle Fill="{StaticResource panelBackgroundBrush2}" Width="2" Height="2" Canvas.Top="9" Canvas.Left="0" />
                                <Rectangle Fill="{StaticResource panelBackgroundBrush2}" Width="2" Height="2" Canvas.Top="13" Canvas.Left="0" />
                                <Rectangle Fill="{StaticResource panelBackgroundBrush2}" Width="2" Height="2" Canvas.Top="17" Canvas.Left="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Top="0" Canvas.Left="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Top="4" Canvas.Left="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Top="8" Canvas.Left="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Top="12" Canvas.Left="0" />
                                <Rectangle Fill="{TemplateBinding TextElement.Foreground}" Width="2" Height="2" Canvas.Top="16" Canvas.Left="0" />
                            </Canvas>
                        </Border>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
Tagged as: , No Comments
21Aug/090

Setting properties – in code vs. in XAML

Something you don't realize when first working with WPF is the different ways to set peroperties in code.
There are times you want to set a property for an item - like a ListBox - and you don't see the property listed in the intellisense.

Here is an exmaple of what I am talking about.
I want to turn off horizontal scrolling on a ListBox so the the content can become variable width and resize with the width of the app.

In XAML this is very easy to do:

<ListBox ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
        <TextBlock TextWrapping="Wrap" HorizontalAlignment="Left">
             Lots and lots of text. Lots and lots of text. Lots and lots of text. Lots and lots of text. Lots and lots of text.
        </TextBlock>
</ListBox>

Here is how to do this in code:

ListBox myList = new ListBox();

// 'Items' property access in the standard way.
myList.Items.Clear();
myList.Items.Add(myItem);

// CanContentScroll is not a property of the ListBox. It is a property of the ScrollViewer in the ListBox's control template.
// These properties can only be set this way:
ScrollViewer.SetCanContentScroll(myList, false);
ScrollViewer.SetHorizontalScrollBarVisibility(myList, ScrollBarVisibility.Disabled);

As you can see, this way of setting the ScrollViewer properties is very logical when you see it. But without know it is done this way, you may not think of it.

This works because the ListBox is a dependency property.

20Aug/090

Find a child UIElement

Here is a nice little method that will find the first occurance of child UIElement.

XAML can get long and complex. This helped me find specific elements so I can set focus on them or do some other type of operation.

Call the method like this

UIElement result = FocusOnFirstElement(myLayoutRoot, typeof(Expander));

Here is the method:

/// <summary>
/// Find the first UIElement of a specific type within the specified root element.
/// UIElements in WPF have child elements under one of the following properties: Content, Child, Items, Children
/// This loops thru itself looking for any child elements.
/// </summary>
/// <param name="rootElement"></param>
/// <param name="typeToFind"></param>
/// <returns>UIElement or null if the element was not found</returns>
public UIElement FocusOnFirstElement(UIElement rootElement, Type typeToFind)
{
    bool found = false;
    UIElement currentElement = rootElement;

    var x1 = currentElement.GetType().GetProperty("Content");
    if (x1 != null)
    {
        var content = currentElement.GetType().GetProperty("Content").GetValue(currentElement, BindingFlags.GetProperty, null, null, null);

        if (content == null)
            return null;

        if (content.GetType() == typeToFind)
            return content as UIElement;

        return FocusOnFirstElement(content as UIElement, typeToFind);
    }

    var x2 = currentElement.GetType().GetProperty("Child");
    if (x2 != null)
    {
        var child = currentElement.GetType().GetProperty("Child").GetValue(currentElement, BindingFlags.GetProperty, null, null, null);

        if (child == null)
            return null;

        if (child.GetType() == typeToFind)
            return child as UIElement;

        return FocusOnFirstElement(child as UIElement, typeToFind);
    }

    var x4 = currentElement.GetType().GetProperty("Items");
    if (x4 != null)
    {
        ItemCollection items = (ItemCollection)currentElement.GetType().GetProperty("Items").GetValue(currentElement, BindingFlags.GetProperty, null, null, null);

        if (items == null)
            return null;

        foreach (var item in items)
        {
            if (item.GetType() == typeToFind)
                return item as UIElement;

            UIElement retunedElement = FocusOnFirstElement(item as UIElement, typeToFind);
            if (retunedElement != null)
                return retunedElement;
        }
    }

    var x5 = currentElement.GetType().GetProperty("Children");
    if (x5 != null)
    {
        UIElementCollection children = (UIElementCollection)currentElement.GetType().GetProperty("Children").GetValue(currentElement, BindingFlags.GetProperty, null, null, null);

        if (children == null)
            return null;

        foreach (var item in children)
        {
            if (item.GetType() == typeToFind)
                return item as UIElement;

            UIElement retunedElement = FocusOnFirstElement(item as UIElement, typeToFind);
            if (retunedElement != null)
                return retunedElement;
        }
    }

    return null;
}
18Aug/090

TreeView in a DataTemplate to display an object containing object references

Some objects contain other objects and it's properties. Displaying these objects is often dificult.
A DataTemplate with a TreeView can do this.

We will use an example of a Customer object with several Address objects as properties of the customer.

Create a DataTemplate for this object in a ResourceDirectory file.

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Customer="clr-namespace:MyNamespace;assembly=MyNamespace">

    <DataTemplate DataType="{x:Type Customer:MyCustomerObject}" x:Key="CustomerObject">
        <TreeViewItem IsExpanded="True">
            <TreeViewItem.Header>
                <StackPanel Orientation="Horizontal">
                    <Label >Customer (ID): (</Label>
                    <Label  Width="100" Content="{Binding Id}"/>
                    <Label >) </Label>
                    <Label  Content="{Binding LastName}"/>
                    <Label >, </Label>
                    <Label  Content="{Binding FirstName}"/>
                </StackPanel>
            </TreeViewItem.Header>
            <TreeViewItem.Items>
                <StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <Label Content="Email: " />
                        <Label Content=" " />
                        <Label Content="{Binding Email}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <Label Content="Mobile Phone: " />
                        <Label Content=" " />
                        <Label Content="{Binding MobilePhone}"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal">
                        <Label Content="Work Phone: " />
                        <Label Content=" " />
                        <Label Content="{Binding WorkPhone}"/>
                    </StackPanel>
                </StackPanel>

                <!-- Address 1 -->
                <TreeViewItem ItemsSource="{Binding Address1}" IsExpanded="True">
                    <TreeViewItem.Header>
                        <StackPanel Orientation="Horizontal">
                            <Label  Content="Home Address:"/>
                        </StackPanel>
                    </TreeViewItem.Header>
                    <TreeViewItem.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label Content="{Binding Street}" />
                                    <Label Content=" " />
                                    <Label Content="{Binding StreetNumber}"/>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label Content="{Binding City}"/>
                                    <Label Content=" " />
                                    <Label Content="{Binding PostCode}"/>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label Content="{Binding Country}"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
                    </TreeViewItem.ItemTemplate>
                </TreeViewItem>

                <!-- Address 2 -->
                <TreeViewItem ItemsSource="{Binding Address2}" IsExpanded="True">
                    <TreeViewItem.Header>
                        <StackPanel Orientation="Horizontal">
                            <Label  Content="Work Address:"/>
                        </StackPanel>
                    </TreeViewItem.Header>
                    <TreeViewItem.ItemTemplate>
                        <DataTemplate>
                            <StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label Content="{Binding Street}" />
                                    <Label Content=" " />
                                    <Label Content="{Binding StreetNumber}"/>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label Content="{Binding City}"/>
                                    <Label Content=" " />
                                    <Label Content="{Binding PostCode}"/>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <Label Content="{Binding Country}"/>
                                </StackPanel>
                            </StackPanel>
                        </DataTemplate>
                    </TreeViewItem.ItemTemplate>
                </TreeViewItem>

            </TreeViewItem.Items>
        </TreeViewItem>
    </DataTemplate>

The Customer and Address objects would look something like this:

class MyCustomerObject
    {
        public string Name { get; set; }
        public string Email { get; set; }
        public string MobilePhone { get; set; }
        public string WorkPhone { get; set; }
        public MyAddress Address1 { get; set; }
        public MyAddress Address2 { get; set; }
    }
    class MyAddress
    {
        public string Street { get; set; }
        public string StreetNumber { get; set; }
        public string City { get; set; }
        public string PostCode { get; set; }
        public string Country { get; set; }
    }

You can set the DataTemplate for the object in code using the ContentTemplate property:

ScrollViewer sv = new ScrollViewer();
sv.ContentTemplate = FindResource("CustomerObject") as DataTemplate;
sv.Content = customer;

For the resource to be found, you have to specify it's location in either the App.xaml or the page where it is used:

<Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Resources/CustomerTemplate.xaml" />
           </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
</Application.Resources>
11Aug/090

Transparent background in a DataTemplate

Pretend you have a ListBox. Instead of assigning ListBoxItems to the list box, you assign a list of objects to it.

When doing so, you must create a DataTemplate for the object so WPF knows how to display the object.

Here is a data template for 'MyObject'. It will display the person's name as 'LastName, FirstName'

<DataTemplate DataType="{x:Type common:MyObject}">
    <Grid Margin="5" x:Name="myObjectPresenter" Background="Transparent" >
        <StackPanel Orientation="Horizontal">
            <Label Content="{Binding LastName}" Margin="0"></Label>
            <Label Content=", " Margin="0"></Label>
            <Label Content="{Binding FirstName}" Margin="0"/>
        </StackPanel>
    </Grid>
</DataTemplate>

Without the transparent background property in the grid, only the text in the ListBox will be clickable. The empty white space around the text will not respond to IsMouseOver or clicking. A background of some sort is required for the mouse to click on or hover ober.
The Background="Transparent" property give the mouse that place to click on without changing the appearance.

5Aug/091

Styling with ControlTemplates Sample

I was reading the post by Ged Mead on his blog about changing the listbox SelectedItem color.

He mentions how to find and download the Simple Styles for WPF UI elements. His directions on how to find the download are out of date. They can be found on this page of the .Net Framework Developer Center.
Or directly download the file from here.

Using the ControlTemplates are pretty strait forward.

Nothing needs to change on your XAML or code-behind pages. You create your ListBoxes, Labels, etc. just as you always did.

Here is an example of a ListBox:

<ListBox Height="70">
    <ListBoxItem Content="First Normal Item" />
    <ListBoxItem Content="Second Normal Item" />
    <ListBoxItem Content="Third Normal Item" />
    <ListBoxItem Content="Fourth Normal Item" />
</ListBox>

The key is in the App.xaml page. You add a MergedDictionaries entry to the ResourceDirectory as follows:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Resources\ListBox.xaml" />
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Application.Resources>

The style for the ListBox will now come from the ListBox.xaml file in the Resources directory.
ListBox and ListBox item are both included in that file.

A 2nd file, not necessary, but helpful is shared.xaml.
This includes all the shared brushes uses in the simple styles. I would highly reccomend using this.

This listbox.xaml file also includes a MergedDictionaries entry for the Shared.xaml file. As you can see, you can make these ResourceDictionaries global or local to a specific file.

  <ResourceDictionary.MergedDictionaries>
    <ResourceDictionary Source="Shared.xaml" />
  </ResourceDictionary.MergedDictionaries>

I can now alter the style of the list box as I wish in the listbox.xaml or Shared.xaml file. I will make the background SelectedItem color Silver instead of the default Dark Blue.

The listbox.xaml file shows the IsSelected property trigger as:

<Trigger Property="IsSelected" Value="true">
  <Setter TargetName="Border" Property="Background"
          Value="{StaticResource SelectedBackgroundBrush}"/>
</Trigger>

The setting for SelectedBackgroundBrush is in the Shared.xaml file. I can set it to pink like this:

<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="Silver" />
Tagged as: 1 Comment
4Aug/090

Binding to a TextBox programmatically

We start with the text box in the XAML:

<TextBox x:Name="tbName" Text="{Binding Name, UpdateSourceTrigger = PropertyChanged}" />

There are 2 important items here.
The 1st is the Binding to the dependancy property declared in the code behind: 'Binding Name'
The 2nd is the UpdateSourceTrigger. Setting it to 'PropertyChanged' triggers the binding whenever the content in the box has been chagned.
Without this, the binding is only updated on the LostFocus event. You would have to click on another form element or somehow change the focus for the changes in the text box to be noticed.
A 3rd property (not shown here) is the Binding Mode. The default for a TextBox is 'TwoWay' so it was not necessary to add it. The other choices are 'OneWay', etc...

In the defination of the XAML file, the DataContext must be defined:

DataContext="{Binding RelativeSource = {RelativeSource Self}}"

Forget this and it will not know where to find the 'Name' property defined in the text box binding.

Define the DependencyProperty in the code behind page of the user control.

public string Name
{
    get { return (string)GetValue(NameProperty); }
    set { SetValue(NameProperty, value); }
}

public static readonly DependencyProperty NameProperty = DependencyProperty.Register("Name", typeof (string),
        typeof (MyUserControl), new UIPropertyMetadata(string.Empty));

When you add 'MyUserControl' to a window or control programmatically, the binding must be spelled out like this:

MyUserControl myUserControl = new MyUserControl();   // Create a new instance of the user control
Binding nameBinding= new Binding();  // Create a new binding
nameBinding.Source = personObject;  // The source of the the object itself, not the specific property of the object
nameBinding.Path = new PropertyPath(personObject.Name);    // The path is specifies what property in the object is bound
nameBinding.Mode = BindingMode.TwoWay;  // Again the mode is set to TwoWay
nameBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;  // Again the trigger is set to PropertyChange
myUserControl.SetBinding(MyUserControl.NameProperty, nameBinding);  // then the binding is set to the dependency property

You can see that several properties (Trigger and Mode) are set both here and in the XAML

27Jul/090

Routed Events – Bubbling

Because I sometimes forget the syntax, a have here a quick bubbling routed event for WPF:

For you have to register the event. Then you have to create the poperty that adds and removed the handlers.

// Register the event
public static readonly RoutedEvent CloseEvent =
    EventManager.RegisterRoutedEvent("Close", RoutingStrategy.Bubble, typeof(RoutedEventHandler),
    typeof(CustomPopupControl));

// Provide CLR accessors for the event
public event RoutedEventHandler Close
{
    add { AddHandler(CloseEvent, value); }
    remove { RemoveHandler(CloseEvent, value); }
}

To manualy raise the event:

RoutedEventArgs args = new RoutedEventArgs(CloseEvent);
RaiseEvent(args);

To listen for the event:

CustomPopupControl popup = new CustomerPopupControl();
popup.Close += new RoutedEventHandler(popup_Closed);
24Jul/090

Binding and Dependency Properties

I found a great reference cheet for Binding over at ndb-tech. Thanks guys!

The quick and dirty way to bind a property to a XAML item is to make that property a Dependency property. Then you can bind it to another property in the XAML.

Here is an example o the XAML:

<Canvas >
            <TextBox Name="tb1" Canvas.Top="{Binding ElementName=thisPopup, Path=CanvasTop}" />
</Canvas>

I found it odd that you have to name your UserControl for it to work. I am sure my syntax is a bit off and it is not necessary.

<UserControl x:Class="Sandbox.UserControl1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="myControl">

The dependency property:

public static DependencyProperty CanvasTopProperty = DependencyProperty.Register("CanvasTop", typeof(double), typeof(PopupControl));
public double CanvasTop
{
    get { return (double)GetValue(CanvasTopProperty); }
    set { SetValue(CanvasTopProperty, value); }
}
24Jul/090

UserControl as a Popup (WPF, C#) – Part 3

To finish off this popup, we need to be able to define it in XAML and wrap it around a block of XAML code. Why? Because defining grids and other complex items can take a LOT of coding in C#.

I thougth Attached properties would be the best way to do this. Attached Properties are very handy and can be used to easily add elements to existing objects.

Creating the PopupControl in XAML would look like this:

<local:PopupControl x:Name="popup2" Title="Our Title">
    <local:PopupControl.Child>
        <StackPanel>
            <Label Content="Just a label"/>
        </StackPanel>
    </local:PopupControl.Child>
</local:PopupControl>

The Attached property to enable this looks like this:

public static readonly DependencyProperty ChildProperty = DependencyProperty.RegisterAttached(
    "Child",
    typeof (UIElement),
    typeof (PopupControl),
    new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnChildChanged)));
public static UIElement GetChild(DependencyObject obj)
{
    return (UIElement)obj.GetValue(ChildProperty);
}
public static void SetChild(DependencyObject obj, UIElement value)
{
    obj.SetValue(ChildProperty, value);
}
private static void OnChildChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    PopupControl p = obj as PopupControl;
    if (p != null && e.NewValue != null)
    {
        p.contentContainer.Children.Clear();
        p.contentContainer.Children.Add(e.NewValue as UIElement);
    }
}

This works very well.

However, I discovered this was not necessary. I could do the same thing with a property. Silly me.
The property:

public UIElement MyChild
{
    set
    {
        contentContainer.Children.Clear();
        contentContainer.Children.Add(value);
    }
}

The PopupControl in created in XMAL like this:

<local:PopupControl x:Name="popup3">
    <local:PopupControl.Title>I like this title</local:PopupControl.Title>
    <local:PopupControl.MyChild>
        <StackPanel>
            <Label Content="Hello Mr. Bean."/>
        </StackPanel>
    </local:PopupControl.MyChild>
</local:PopupControl>

For a good article on attached properties and how they can be used, look at this article: http://en.csharp-online.net/WPF_Concepts%E2%80%94Attached_Properties

Now I have a popup that does everything we want it to do, but is not a popup at all. Nice!