WPF Child Window Implementation 1. Customize title bar

In form application, there has a component named MDI, which we can use it to show a child window in parent window. But it's a character of form application, WPF not supposes such thing. But sometimes we need to show a child window stuff in wpf application in some special scenarios, the behavior simply like that in form application would be appreciated. Although there doesn't exist MDI,  some decorations for control would help us achieve that goal as well.

Below is a simple example.

1. Create a WPF application, File>Create project>Choose WPF application. And named this app TestApp. Solution prepared as below


After adding needed files the solution is like below


2. The MainWindow is our host window of child windows. Add a canvas as stage for its child windows, add a button that show child window when we click it.

<pre name="code" class="html"><Window x:Class="TestApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="450" Width="600">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>
        <Border BorderThickness="2" BorderBrush="Orange" Grid.Row="0">
            <Canvas Name="canvasStage" />
        </Border>
        <Button Grid.Row="1" Content="Show" FontSize="16" Margin="2"
                Background="LightCoral" Click="Button_Click"/>
    </Grid>
</Window>

3.Add a class Named LayoutControl.cs, which would implement some common functions and our "child window" would inherit it.

using System.Windows;
using System.Windows.Controls;

namespace TestApp
{
    public class LayoutControl : UserControl
    {
        public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
            "Title",
            typeof(string),
            typeof(LayoutControl),
            new PropertyMetadata("My Window"));

        public string Title
        {
            get { return (string)this.GetValue(TitleProperty); }
            set { this.SetValue(TitleProperty, value); }
        }

        public LayoutControl()
            : base()
        {
            this.Style = (Style)Application.Current.Resources["ChildWindowStyle"];
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            Button btnClose = this.Template.FindName("closeBtn", this) as Button;
            Button btnMaxi = this.Template.FindName("maxinumBtn", this) as Button;
            Button btnMini = this.Template.FindName("mininumBtn", this) as Button;

            // Close event
            if (btnClose != null)
            {
                btnClose.Click += (s, e) => ((Panel)this.Parent).Children.Remove(this);
            }

            // Maxinum event
            if (btnMaxi != null)
            {
                btnMaxi.Click += (s, e) =>
                    {
                        Panel parent = (Panel)this.Parent;
                        this.Margin = new Thickness(0);
                        this.Height = parent.ActualHeight;
                        this.Width = parent.ActualWidth;
                    };
            }

            // Mininum event
            if (btnMini != null)
            {
                btnMini.Click += (s, e) =>
                {
                    this.Visibility = Visibility.Collapsed;
                };
            }
        }

    }
}


4. We need to create minimum button, maximum button and close button for child window. To implement this, we could create a style, user control could turn to "window" when apply this style. We add this style in App.xaml 

<Application x:Class="TestApp.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="MainWindow.xaml"
             xmlns:common="clr-namespace:TestApp">
    <Application.Resources>
        <Style x:Key="ChildWindowStyle" TargetType="{x:Type common:LayoutControl}">
            <Setter Property="BorderBrush" Value="Silver"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="Height" Value="300"/>
            <Setter Property="Width" Value="400"/>
            <Setter Property="Margin" Value="20"/>
            <Setter Property="Background" Value="#FFE6E6E6"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type common:LayoutControl}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}"
                                BorderThickness="{TemplateBinding BorderThickness}">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="20"/>
                                    <RowDefinition Height="*"/>
                                </Grid.RowDefinitions>

                                <!--Make window has shadow-->
                                <Rectangle Fill="{TemplateBinding Background}" Grid.RowSpan="2">
                                    <Rectangle.Effect>
                                        <DropShadowEffect BlurRadius="10" ShadowDepth="3"/>
                                    </Rectangle.Effect>
                                </Rectangle>

                                <!--Title bar-->
                                <Grid Grid.Row="0" Background="{TemplateBinding BorderBrush}">
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
                                        <!--Minimum button-->
                                        <Button Name="mininumBtn" Content="⚊" BorderThickness="0" Background="Transparent"/>
                                        <!--Maximum button-->
                                        <Button Name="maxinumBtn" Content="⬒" Margin="3,0" BorderThickness="0"
                                            Background="Transparent"/>
                                        <!--Close button-->
                                        <Button Name="closeBtn" Content="✖" Margin="0,0,3,0" BorderThickness="0"
                                            Foreground="Red" Background="Transparent"/>
                                    </StackPanel>
                                </Grid>

                                <TextBlock Text="{TemplateBinding Title}" HorizontalAlignment="Center" VerticalAlignment="Center"/>

                                <ContentPresenter Grid.Row="1"/>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </Application.Resources>
</Application>

5. Add a wpf UserControl named ChildWindow.xaml, we would use it to mock show MDI scenario.

The code in ChildWindow.xaml

<common:LayoutControl x:Class="TestApp.ChildWindow"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" Title="Hello"
             d:DesignHeight="300" d:DesignWidth="300"
             xmlns:common="clr-namespace:TestApp">
    <Grid Background="White">
        <TextBlock Text="I am child window" FontSize="16" Margin="9"/>
    </Grid>
</common:LayoutControl>
The code in ChildWindow.xaml.cs
namespace TestApp
{
    /// <summary>
    /// ChildWindow.xaml 的交互邏輯
    /// </summary>
    public partial class ChildWindow : LayoutControl
    {
        public ChildWindow()
        {
            InitializeComponent();
        }
    }
}

6. Then we need to show child window in main window, here we design to show it when we click the show button in Main Window

The code in MainWindow.xaml.cs

using System.Windows;

namespace TestApp
{
    /// <summary>
    /// MainWindow.xaml 的交互邏輯
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ChildWindow window = new ChildWindow();
            this.canvasStage.Children.Add(window);
        }
    }
}

Finally, run the app then you can see the results.


Click the Show button


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章