WPF Winodw/Page/Control 見た目・共通動きの継承

継承元カスタムコントロールの作成

継承元となる親デザインは、カスタムコントロールで作ります。

  1. ソリューションエクスプローラーで、プロジェクトを右クリック
  2. 「追加」⇒「新しい項目」を選択
  3. 「カスタムコントロール(WPF)」を選択し、名前に「BaseWindow」を入力し、「追加」を選択
継承元クラスの編集

追加したBaseWindow.csを開いて、デフォルトで継承されているControlを変更します。共通で行いたいことをここで定義します。

  • Control ⇒ Window
  • 共通メニューアリアをここで定義しますが、具体的なメニューアイテムは個々ウインドウのロード時に追加します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace WpfApp
{
    public abstract class BaseWindow : Window
    {
        static BaseWindow()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(BaseWindow), new FrameworkPropertyMetadata(typeof(BaseWindow)));

            // 背景色をWindowBrushにしておく
            BackgroundProperty.OverrideMetadata(typeof(BaseWindow), new FrameworkPropertyMetadata(SystemColors.WindowBrush));
        }

        public Menu TopMenu { get; set; }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            TopMenu = GetTemplateChild("topMenu") as Menu;
        }

        protected void BaseWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // init topPanel 
            InitTopMenu();
        }

        protected abstract void InitTopMenu();
    }
}
Generic.xamlの編集

{プロジェクトルート}\Themes\Generic.xaml に共通的な見た目(デザイン)を定義します。

<?xml version="1.0"?>
<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ctl="clr-namespace:WpfApp">

    <Style TargetType="{x:Type ctl:BaseWindow}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ctl:BaseWindow}">
                    <!-- ここに見た目を作っていく -->
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                        <DockPanel>
                            <!-- 共通メニューアリア -->
                            <StackPanel DockPanel.Dock="Top" Name="topPanel"
                                       Background="LightGoldenrodYellow" Height="20">
                                <Grid>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="80" />
                                    </Grid.ColumnDefinitions>
                                    <Menu Grid.Column="0" Name="topMenu" 
                                          Background="LightGoldenrodYellow" >
                                    </Menu>
                                    <TextBlock Grid.Column="1" VerticalAlignment="Center"
                                        TextAlignment="Center">利用ユーザー</TextBlock>
                                </Grid>
                            </StackPanel>
                            <StackPanel DockPanel.Dock="Bottom" Name="bottomPanel"
                                       Background="LightGoldenrodYellow" Height="20">
                                <TextBlock Margin="10,0,0,0" VerticalAlignment="Center" >
                                    メッセージ・ステータスを表示するエリア
                                </TextBlock>
                            </StackPanel>
                            <ContentPresenter />
                        </DockPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>


    <Style TargetType="{x:Type local:CustomControl1}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:CustomControl1}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
継承元クラスを変更

BaseWindow を継承するウインドウの .xaml および .xaml.cs に継承元クラスを変更します。

ChildWindow.xaml
<local:BaseWindow x:Class="WpfApp.ChildWindow"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      ・・・
      Loaded="BaseWindow_Loaded">
・・・
</local:BaseWindow>
ChildWindow.xaml.cs
public partial class ChildWindow : BaseWindow
{
    public ChildWindow()
    {
        InitializeComponent();
    }
    protected override void InitTopMenu()
    {
        if (TopMenu == null)
        {
            throw new System.Exception("TopMenuがNullになっています。");
        }

        MenuItem mi = new MenuItem();
        mi.Header = "新規";
        TopMenu.Items.Add(mi);
    }
}

・参考: