Charlie
Charlie

Reputation: 1179

Same menubar or toolbar for all windows in a WPF application

I want to create a wpf application with a menubar. The Menubar has some clickable elements, which opens a new window. Because the menubar is the same on every window, I want to create the menubarcode just once.

I read here how to create a menubar (What is the accepted way to get a main window with menubar and toolbar in WPF?):

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        x:Name="self"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Menu Grid.Row="0">
            <MenuItem Header="File">
                <MenuItem Header="Open" />
                <MenuItem Header="Close" />
            </MenuItem>
        </Menu>
        <ToolBar Grid.Row="1">
            <Button Content="Foo" />
            <Button Content="Bar" />
        </ToolBar>
    </Grid>
</Window>

I read also the question for the same header an footer for alle wpf windows: Same header & footer in all WPF windows. There they suggest a usercontrol.

The Question How to make a Template Window in WPF? doesn't solve my issue. Is it possible to add clicklistener to the template? I do not want to implement all clicklistener on every window. My menubar/toolbar only opens some other windows. Only for diplaying static content the solution would work.

What is the best practice for this kind of problem?

Upvotes: 4

Views: 2378

Answers (2)

Siim Haas
Siim Haas

Reputation: 505

You can create a style where you define template for a window.

<Style x:Key="MyWindowStyle" TargetType="Window">
    //Some other shared properties
    <Setter Property="..." Value="..."/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Window}">
                <StackPanel>
                    //This will represent a header/toolbar
                    <StackPanel />
                    <ContentPresenter />
                    //This will represent a footer
                    <StackPanel />
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Add that style to Application Resources:

<Application x:Class="Wpf.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>
        <Style x:Key="MyWindowStyle" TargetType="Window">
            //...
        </Style>
    </Application.Resources>
</Application>

You can use it followingly:

<Window x:Class="Wpf.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:viewModels="clr-namespace:Wpf.ViewModels"
        mc:Ignorable="d"
        Style="{StaticResource MyWindowStyle}"> //We apply that style to this window

    <TextBlock Text="This will be put in 'ContentPresenter' between those stackpanels"/>

</Window>

If your toolbar/header is complicated then you can pull it into separate usercontrol.
If you want to have 'base' window for shared code-behind functionality then take a look at How do I create a base page in WPF?

Upvotes: 1

davlast
davlast

Reputation: 21

You can use DataTemplates.

DataTemplate:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                xmlns:local="clr-namespace:WpfApplication1">
    <DataTemplate DataType="{x:Type local:MenuBar}">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition Height="Auto" />
                <RowDefinition Height="*" />
            </Grid.RowDefinitions>
            <Menu Grid.Row="0">
                <MenuItem Header="File">
                    <MenuItem Header="Open" />
                    <MenuItem Header="Close" />
                </MenuItem>
            </Menu>
            <ToolBar Grid.Row="1">
                <Button Content="Foo" />
                <Button Content="Bar" />
            </ToolBar>
        </Grid>
    </DataTemplate>
</ResourceDictionary>

Code behind:

namespace WpfApplication1
{
    public class MenuBar
    {
        //some logic here
    }
}

Example of use in your code:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Name="self"
    Title="MainWindow" Height="350" Width="525">
    <ContentPresenter Content="{Binding MenuBar}"/>
</Window>

Where Menubar is property of type MenuBar.

Upvotes: 2

Related Questions