Tag Archive: wpf

Working with the WPF TextBlock control.

Introduction
Setting a TextBlock’s Content
Formatting Text
Using Controls with Formatted Text

Introduction

In WPF there are two very similar controls Label and TextBlock, and I’m going to cover TextBlock and why its so useful. First, what is the TextBlock control? A first look at the Msdn documentation.

Provides a lightweight control for displaying small amounts of flow content.

Well, that doesn’t tell that much about the control. A more accurate description would be that its a lightweight control for displaying various forms of formatted text and controls in a flow layout. Specifically, the TextBlock control can contain other controls, and arbitrary text that you can format with different font styles, colors, and brushes. Because it can contain other controls, it is actually much more than a `Text`Block, and I’m not sure why they named it TextBlock considering.

Setting a TextBlock’s Content

For demonstration, I will start with a small WPF Windows Application that contains just a TextBlock control containing the text Hello World!.

<Window x:Class="TextBlockDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Top"> 
            Hello World!
        </TextBlock>
    </Grid>
</Window>
TextBlockDemo_HelloWorld

An empty window with a TextBlock

There are two ways you can set text for a TextBlock. The first is the most obvious, and that is to set the Text property.

<TextBlock Text="Hello World!" HorizontalAlignment="Stretch" VerticalAlignment="Top">

The second is by setting the inner value of the control like I did in the demo application. Both methods give the same result for displaying Hello World!, but only setting the inner value of the TextBlock control gives us access to the true potential of the control. The Text property itself can only be used to display an arbitrary System.String. Shown below is the source code from the TextBlock metadata of its Text property.

//
// Summary:
//     Gets or sets the text contents of a System.Windows.Controls.TextBlock.
//
// Returns:
//     The text contents of this System.Windows.Controls.TextBlock. Note that all
//     non-text content is stripped out, resulting in a plain text representation
//     of the System.Windows.Controls.TextBlock contents. The default is System.String.Empty.
[Localizability(LocalizationCategory.Text)]
public string Text { get; set; }

Because the TextBlock can contain multiple controls by using its inner value, we can add things like buttons or other controls.

<Window x:Class="TextBlockDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Top">
            Hello World!
            <Button Content="Click me!" />
        </TextBlock>
    </Grid>
</Window>

A TextBlock containing text along with a Button control.

One of the most common questions from those just entering the WPF world is why doesn’t the button display on a new line even though in the Xaml the Button element is on its own line? Placing elements on a new line doesn’t necessarily do anything, and for a TextBlock control, adding a new line is actually done using the LineBreak element.

<Window x:Class="TextBlockDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Top">
            Hello World!
            <LineBreak />
            <Button Content="Click me!" />
        </TextBlock>
    </Grid>
</Window>

A TextBlock control with text, a button, and a line break.

I won’t cover any more about nested controls in the TextBlock. Once you understand that a control can contain other controls, the rest depends on your understanding of understanding the layout and styling mechanisms of WPF. The usefulness of truly comes from the ability to format strings of text without using multiple controls.

Formatting Text

Formatting text is done using an element called a Run which is defined as a inline-level flow content element intended to contain a run of formatted or unformatted text. Using a Run, you can style seperate segments of text using colors, brushes, and styles.

<Window x:Class="TextBlockDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Top">
            <Run Foreground="Red">Hello</Run>
            <Run Foreground="Blue">World!</Run>
        </TextBlock>
    </Grid>
</Window>

A TextBlock containing the text 'Hello World!' split into two runs, one red and one blue.

You can see that it was very easy to style the text to be red and blue. Now let’s add a LinearGradientBrush to the second run and give it a larger font with a bold style.

<Window x:Class="TextBlockDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Top">
            <Run Foreground="Red">Hello</Run>
            
            <LineBreak />
            
            <Run Text="World!" FontSize="24pt" FontWeight="Bold">
                <Run.Foreground>
                    <LinearGradientBrush StartPoint="0,1" EndPoint="0,0">
                        <GradientStop Offset="0" Color="Navy" />
                        <GradientStop Offset="1" Color="DodgerBlue" />
                    </LinearGradientBrush>
                </Run.Foreground>
            </Run>
        </TextBlock>
    </Grid>
</Window>

A TextBlock run with its Foreground set to a LinearGradientBrush

Just like the TextBlock, a Run can contain its text in either its Text property, or its inner value. Since we want to use its inner value to set some text effects, it was moved from the inner value to the Text property. The FontSize and FontWeight properties were also added, along with our Run.Foreground element that contains our linear gradient effect.

Using Controls with Formatted Text

Often times you may want to do something like have a piece of text actually contain a link to some resource. I had a need for this myself in one of my dialogs in my licensing modules; I need it to display a link to a product page. A TextBlock can contain both controls and runs, which makes for great flexibility. A Run however, cannot contain a control so its important to make note of that.

<Window x:Class="TextBlockDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock HorizontalAlignment="Stretch" VerticalAlignment="Top">
            <Run Text="This is some text containing a " />
            <Hyperlink NavigateUri="http://danderson.io/">link to a page.</Hyperlink>
        </TextBlock>
    </Grid>
</Window>

A TextBlock containing a HyperLink.

The cool thing about this is that because a HyperLink is its own control, it can contain its own styling and behaviors.

There’s not much else to say about the TextBlock because it really is a simple control. It’s just really flexible and when used correctly can be a very easy way to display lots of formatted text to a user. The ability to contain controls that can also have their own styles and behaviors is really cool, but I still think the WPF team should have chosen a better name than TextBlock, because its much more than just arbitrary text.

Avoiding a deadlock when creating a STA thread and using Dispatcher.

I have always been pretty articulate and careful when writing multi-threading code, but today I wrote my first deadlock that had me baffled for a few minutes. I’m working on a licensing dll that handles a lot of processing, and it also handles some user interface display using WPF Windows. I cannot guaruntee whether or not the calling thread will be a single-threaded apartment, because the assembly that implements it might be a console or a window, but the assembly doesn’t know which, or which threading model it uses. The good news is that System.Threading provides very rich types to be able to check for this as well as handle it.

First lets take a look at actually checking for the threading model, and creating an STA thread if needed.

if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) {
    Thread thread = new Thread(() => {
        // ...
    });

    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
}

You can see that the code to check for the current threading apartment isn’t anything hard, and neither is setting the apartment state. Now my requirement was that the WPF Window be shown modal by calling Window.ShowDialog so I could consume the DialogResult and continue processing in the licensing service. To do this I created the Window in the newly created STA thread.

if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) {
    ActivateWindowController controller = new ActivateWindowController();
    ActivateWindow window = null;

    bool? dialogResult = null;

    Thread thread = new Thread(() => {
        window = new ActivateWindow(controller);
        dialogResult = window.ShowDialog();
    });

    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join();
}

There’s nothing too exciting about any of this either. I’m using the Model-View-Controller (MVC) pattern so I have a ActivateWindowController that gets passed to the ActivateWindow constructor. Because we need the Window to run in a single-threaded apartment, I do the actual instantiation in the new Thread. Then I make a call to ShowDialog() and consume the result. The last bit is adding thread.Join(); so the calling thread is blocked until the new thread terminates, which is when the dialog is closed.

Now I’ll try to explain what ActivateWindowController does as best as I can. When ActivateWindow is loaded, the WPF stack invokes the Loaded event handler. The code isn’t anything special, so I’ll just show it.

public partial class ActivateWindow : Window
{
    /// <summary>
    /// Initializes a new instance of the DCOMProductions.Licensing.Windows.LicenseWindow class.
    /// </summary>
    public ActivateWindow(ActivateWindowController controller) {
        InitializeComponent();
        _controller = controller;
    }

    #region Controller Members

    private ActivateWindowController _controller;

    private void Window_Loaded(object sender, RoutedEventArgs e) {
        _controller.ActivateComplete += ActivateComplete;
        _controller.Activate();
    }

    private void ActivateComplete(object sender, ActivateWindowController.ActivateEventArgs e) {
        DialogResult = e.Result == ActivationResult.Passed ? true : false;
    }

    #endregion
}

When the Loaded event handler is invoked, a call to ActivateWindowController.Activate() is made. What this method does is spin off a new Task by calling Task.Factory.StartNew(...) and consumes a WCF service. In short, it means another thread. When the task completes, it invokes Task.ContinueWith(...) which is responsible for wrapping up the result and delegating everything to the proper thread.

.ContinueWith((task) => {
    CloseDialogCallback method = new CloseDialogCallback(() => {
        OnActivateComplete(new ActivateEventArgs(result));
    });
    _Dispatcher.BeginInvoke(method, null);
});

Now it is important to note here that _Dispatcher is a private instance that was initialized in the constructor of ActivateWindowController. In short, the dispatcher lives on the UI thread of the Window. The dispatcher is required to delegate calls to the correct thread, in this case we want to delegate the callback method to the UI thread. And remember, the UI thread is the STA thread I created earlier.

I highlighted the last line, because this is where the deadlock is introduced. When _Dispatcher.BeginInvoke(method, null); is called, it schedules asynchronously the callback to be executed on the thread that the dispatcher was created on. And remember, the thread that _Dispatcher was created on is the same thread that the ActivateWindowController instance was created on. Let’s double check that.

if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA) {
    ActivateWindowController controller = new ActivateWindowController();
    ActivateWindow window = null;

    bool? dialogResult = null;

    Thread thread = new Thread(() => {
        window = new ActivateWindow(controller);
        dialogResult = window.ShowDialog();
    });

    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.Join();
}

Well, hopefully by now you realize the problem and why there is a deadlock. ActivateWindowController is not being instantiated on our STA thread. So what’s happening here is when _Dispatcher.BeginInvoke is called, it is scheduling the callback to execute on the same thread we told to block by calling thread.Join(). Because that thread is blocked and the dialog can’t return until the callback is executed by the dispatcher, I have a blocked thread and a scheduled callback that will never run; eg. a deadlock.

The fix is to instantiate ActivateWindowController on the STA thread I created which is where we want the dispatcher to delegate the callback to anyway. This resolves the deadlock problem. It’s important to watch out for little quirks like this. It didn’t take me long to realize what created the deadlock, but I think on most days it would have taken me much longer to figure it out. The most important thing to remember is that this is not specific to a Dispatcher, and that it applies to multi-threading regardless.

Showing a splash screen in WPF from an external assembly or class library.

This isn’t anything special, but the documentation on Msdn for System.Windows.SplashScreen is lacking. Basically I am writing a licensing system and during debugging the WPF stack can take many seconds to load. When making changes to this system sometimes it may result in a failure, but I may not see it for a few seconds. I wanted something to display during this time period so I know at least something is going on.

I knew that WPF has built-in support for splash screens by setting the Build Action of an image in my project to Splash Screen in the properties window, but the problem is that this only works for the project the image is embedded into, and only if its a WPF Application project. My requirements are that I can display the splash screen from my licensing dll (class library) when my licensing service is invoked. This means that the licensing dll would contain the image to display, and contain the logic to show the splash.

Luckily, SplashScreen exposes a SplashScreen(Assembly, String) constructor which allows you to do just this. To accomplish this task, all you need to do is add your image to your class library project, set its build action to Splash Screen, and then write three lines of code.

Assembly asm = Assembly.GetAssembly(GetType());
SplashScreen splash = new SplashScreen(asm, "SplashScreen.png");
splash.Show(true);

The first line is simple; we are just getting the assembly that contains the splash resource (in this case my licensing library). The second line takes the assembly as an argument, and we pass in the name of the image. Next we simply call splash.Show(true); which actually displays the image, and because we passed in true as the argument, it will automatically be closed by the WPF stack once the first window is constructed, loaded, and displayed.

Make sure that you add your image to the root of your project, so that the WPF stack can find it.

I haven’t looked into it because I don’t want to spend a lot of time on a task that doesn’t mean much, but placing the image at other hierarchical locations in your project structure can cause the embedded resource path string to change, and it may not be found by the WPF stack internally. It’s probably possible to specify a qualified path using the second constructor parameter, but I was not able to get it to work using a fully qualified resource path string.