22

So i am building an application that will have lots of windows, all with the same basic layout:

  1. A main Window
  2. A logo in the top corner
  3. A title block
  4. A status displayer down the bottom
  5. An area for window specific controls.

At the moment i have to recreate this structure in every window. Ideally i want this layout to be coded in a single place, perhaps into a custom Window subclass for ease of use. Does anyone have any clues for how to get started, or previous experience with similar problems?

NoizWaves
  • 2,650
  • 6
  • 28
  • 32

4 Answers4

36

You can create a new ControlTemplate that targets a window to accomplish this as shown below.

<ControlTemplate x:Key="WindowControlTemplate1" TargetType="{x:Type Window}">
    <Border 
        Background="{TemplateBinding Background}" 
        BorderBrush="{TemplateBinding BorderBrush}" 
        BorderThickness="{TemplateBinding BorderThickness}"
        >
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="0.93*"/>
                <RowDefinition Height="Auto"/>
            </Grid.RowDefinitions>

            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0.21*"/>
                <ColumnDefinition Width="0.79*"/>
            </Grid.ColumnDefinitions>

            <ContentPresenter 
                Grid.ColumnSpan="2" 
                Grid.Row="1" 
                Content="{TemplateBinding Content}" 
                ContentTemplate="{TemplateBinding ContentTemplate}"
                />
            <ResizeGrip 
                HorizontalAlignment="Right" 
                x:Name="WindowResizeGrip" 
                VerticalAlignment="Bottom" 
                IsTabStop="False" 
                Visibility="Collapsed" 
                Grid.Column="1" 
                Grid.Row="2"
                />
            <TextBlock Text="My Logo" />
            <TextBlock Grid.Column="1" Text="My Title"/>
            <StatusBar Height="20" Grid.ColumnSpan="2" Grid.Row="2"/>
        </Grid>
    </Border>

    <ControlTemplate.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="ResizeMode" Value="CanResizeWithGrip"/>
                <Condition Property="WindowState" Value="Normal"/>
            </MultiTrigger.Conditions>
            <Setter Property="Visibility" TargetName="WindowResizeGrip" Value="Visible"/>
        </MultiTrigger>
    </ControlTemplate.Triggers>
</ControlTemplate>
Ian Oakes
  • 10,153
  • 6
  • 36
  • 47
  • I would like to customize the non-client area of the Window. When I try to customize the template I can only change the visual representation of the client area. I would like to add a content control or any other controls to the title bar. – Shameel Mohamed Feb 04 '23 at 10:42
6

If you're brave enough to take a big architectural shift you could consider CompositeWPF (previously codenamed Prism) from the Patterns & Practices guys at Microsoft.

Of interest to you would be the ability to define "regions" in a shell (i.e. window) and then using views to fill the regions. It uses the Model-View-Presenter pattern to allow independent development of "views" from the model than can be easily be relocated over time as the shell only defines regions and is not coupled directly to what is placed in to it. Principally this helps decouple the shell from the views and the views from each other and make it easier to unit-test ... blah, blah blah.

It is a big jump and something that will slow you down to begin with, although your situation is one of the types of applications that CompositeWPF is meant to address.

As part of CompositeWPF you will need to take on board various patterns that can confuse newcomers, e.g. The UnityContainer, inversion-of-control, MVP (or Model/view/view-model) and dependency injection.

I can remember when I first started with the sample apps being puzzled because it is not obvious how on earth the some of the views were even being created! The unity container will instantiate objects and call parameterised constructors magically.

CompositeWPF is an elegant solution to your question but not a simple or straightforward one. Having used CompositeWPF in my last project I intend to use it again for the next appropriate application.

Rhys
  • 4,511
  • 2
  • 23
  • 32
  • Thanks for your detailed introduction to CompositeWPF. I downloaded the Composite Application Guidance for WPF and got more confused, I was wondering if there any simple example for a new comer to learn? – Picflight Feb 25 '09 at 20:00
  • @Picflight: Here's a link to a Brian Noyes article on DevX http://www.devx.com/codemag/Article/40165/1763 . Where ever you can get sample code, use the debugger to help you learn how things work. Place breakpoints on the constructors of classes and walk up the call stack to see how it works. – Rhys Feb 26 '09 at 17:39
2

The most simple approach is to create WPF a "Page" for the window specific controls and place a "Frame" in the main window. You can even create a nice navigation this way.

Hades32
  • 914
  • 2
  • 9
  • 12
-6

why exactly are you using "lots of windows?" Why not just a single window with a tab control? Or a single window with user controls?

Regardless, to answer your question, usercontrols are one way you want to get the functionality that you're describing as wanting.

Create a new Window class, and have it have a "Childrens" property which allows for an object to get embedded into the dock panel where you want the "window specific controls" to go.

As you launch new windows, instantiate the window type, and a user control with the specific controls, add the user control to the Children property of your window, and then show the window. You can even tie up event handlers, DataContexts and what not at this time.

Stephen Wrighton
  • 36,783
  • 6
  • 67
  • 86
  • 1
    Why so many downvotes? Seems like a valid question to me, maybe not the ideal answer but it is definitely worth considering for the right situation. – MikeKulls Sep 02 '14 at 07:25
  • 1
    Because while it presents a solution, it doesn't really answer the question. Additionally, it is a highly brute force method of a solution. In all actuality, I'd describe it as a WINFORMS method of solving it over a WPF one (which the selected answer is). – Stephen Wrighton Sep 02 '14 at 13:18
  • Maybe you are focusing too much on the "single window with a tab control" bit?? The single window with interchangeable user controls is a perfectly valid solution in the right situation. It's the only solution that avoids code duplication, if you have more than 1 window then code of some sort, no matter how small, needs to be duplicated in each of those windows. If there are changes required then that code needs to be changed in multiple locations. It's not a deal breaker either way but it is something certainly worth considering. – MikeKulls Sep 17 '14 at 03:26
  • I take that back. A single window with a tab control is also a perfectly valid solution. Dynamic tab controls are all the rage these days as they provide a much more user friendly method of navigating between windows. I think people are down voting this because they are assuming Stephen meant a tab control with a fixed number of tabs. – MikeKulls Oct 14 '14 at 02:09
  • Usage ex: Multiple monitors where you track, compare and manage realtime informations from your application and other sources (like multiwindow webbrowser, other company apps...) You need to be able to move and resize windows with various datas around, not lock them in a single window nor expand that window on mutiple monitors that blocks other informations. I didn't downvote though (which I believe, are due to the strong emphasis on "why lots of windows", should have simply been a reminder/suggestion to avoid doing an overkill of a multiple interfaces app where child controls would suffice). – Karl Stephen Jan 16 '22 at 07:08