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?
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.
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?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With