Sep 30 2012

Setting the Display for a WPF Application

Category: Joel Ivory Johnson @ 14:56

I'm working on a presenttion project for which I needed to set the display on which a set of WPF applications are running. There's a total of 6 WPF applications that will be running on the same machine at once. Each application is going to be running on a different display. I thought I would share the solution that I used to control which display that each instance of this application went to. 

The first thing I needed to do was to retrieve the information on how how many displays that the computer has and the coordinates of each display. The computer creates a single (logical) display and maps each display device to cover a range of coordinates on this logical display. So I needed to retrieve a list of the displays and the coordinates to which it is mapped. The class available for doing this is in in the System.Windows.Forms library. Since I wasn't making a Windows Forms application I didn't want to add a using directive that would include the entire library; if I did there would be some class names that exists both in this name space and a WPF name space that I was using that could cause some resolution issues. So I only included the single class from the namespace. 

using Screen=System.Windows.Forms.Screen

The Screen class contains a member named <code>AllScreens</code> that contains a collection of <code>Screen</code> objects that give the information on each screen. If you wanted to make a simple WPF program that displayed all of the screens and their positions it only takes a few lines of code. The following is the code for the code-behind and the XAML for such a program. 

public partial class MainWindow : Window

    public MainWindow()
        this.DataContext = Screen.AllScreens;
<Window x:Class="ScreenTest.MainWindow"
        Title="MainWindow" Height="350" Width="525">
        <ListBox ItemsSource="{Binding}">
                    <StackPanel Orientation="Vertical">
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="100" />
                                <ColumnDefinition Width="100" />
                            <TextBlock Text="{Binding DeviceName}" />
                            <TextBlock Grid.Column="1" Text="{Binding WorkingArea.X}" />
                            <TextBlock Grid.Column="2" Text="{Binding WorkingArea.Y}" />
                            <TextBlock Grid.Column="3" Text="{Binding WorkingArea.Width}" />
                            <TextBlock Grid.Column="4" Text="{Binding WorkingArea.Height}" />

Screenshot of the interface running


For the programs that I'll be running I've set device name for the program's intended display in a configuration file. The typical display name for the first display is \\.\DISPLAY1. I've made a method that will take the indended display name, try to find it, and set the position and size of the window accordingly.

void SetTargetDisplay()
    var targetDeviceName = Settings.Default.DisplayDevice;
        // see if the device name specified exists here. It's possible
        // this was configured  to  run on a different machine and the 
        // configured device might not exists
        var screen = (from s in Screen.AllScreens 
             where s.DeviceName.ToLower().Equals(targetDeviceName.ToLower()) 
             select s).FirstOrDefault();
        if (screen != null)
            Left = screen.WorkingArea.Left;
            Top = screen.WorkingArea.Top;
            Width = screen.WorkingArea.Width;
            Height = screen.WorkingArea.Height;

If the display doesn't exists (which could happen because of a typographical error or the program having been configured for another machine) then the method will just ignore the request.