吵吵   2014-12-01  阅读:5,740

那些年做windows程序,界面是很令人头疼的一个问题。一般自带的那些窗口和控件都是很丑的,第三方的界面库又不稳定,万般无奈的时候,就只有响应WM_PAINT消息自己慢慢画,但是觉对是一个非常艰苦的过程。

WPF出现后,很多问题都引刃而解,一些控件改改背景,改改字体变得非常的容易,最重要的是,后续版本都已经支持动画了,想当年要实现动画是个多么不容易的事情,现在几句代码就解决了。

会HTML的人大概就很熟悉XAML的写法了!

我们今天要探讨的问题是,如何实现一个窗口的风格(style),让所有的窗口都继承这样同样的风格,包括标题栏,放大、缩小和关闭按钮。

那么,我们可不可以就建立一个Base窗口,然后将这个窗口的风格给设计好之后,所有的窗口都继承自他呢?

答案是否定的,我们一定要知道,窗口是一个类,它可以继承,但是风格(XAML)文件是继承不了的。

所以我们能够做到的是:

1、窗口类继承,BaseWindow封装窗口最大化按钮,最小化按钮的点击等事件。

2、风格(Style)就利用属性来设置,把window看成一个控件,利用Style=“BaseWindowStyle”就可以了。

以下是详细的步骤:

1、新建一个BaseWindowStyle的模板文件。点击项目名称,右键“添加”->”资源字典”->输入名称为“BaseWindowStyle.xaml”,然后将以下的末班文件拷贝进去:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <ControlTemplate x:Key="WindowTemplateKey"
                     TargetType="{x:Type Window}">
        <Border Background="{TemplateBinding Background}"
                BorderBrush="{TemplateBinding BorderBrush}"
                BorderThickness="{TemplateBinding BorderThickness}">
            <Grid>
                <AdornerDecorator>
                    <ContentPresenter />
                </AdornerDecorator>
                <ResizeGrip Visibility="Collapsed"
                            IsTabStop="false"
                            HorizontalAlignment="Right"
                            x:Name="WindowResizeGrip"
                            VerticalAlignment="Bottom" />
            </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>
    <ControlTemplate x:Key="BaseWindowControlTemplate" TargetType="{x:Type Window}">
        <DockPanel LastChildFill="True">
            <!--外边框-->
            <Border Width="Auto"
                    Height="Auto"
                    DockPanel.Dock="Top"
                    Background="#FF7097D0"
                    CornerRadius="0,0,0,0"
                    x:Name="borderTitle">

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

                        </ColumnDefinition>

                    </Grid.ColumnDefinitions>


                    <TextBlock Grid.Column="0"   Margin="20,0,2,2"  Name="Title" VerticalAlignment="Top" FontSize="20" 
          Foreground="White" Text="{TemplateBinding Title}"/>
                    <StackPanel Grid.Column="1" HorizontalAlignment="Right" 
                            Orientation="Horizontal">

                        <!--最小化按钮-->
                        <Button x:Name="btnMin" Content="M" Margin="2,2,2,2" Style="{DynamicResource MinButtonStyle}"/>


                        <!--最大化按钮-->
                        <Button x:Name="btnMax" Content="M" Margin="2,2,2,2" Style="{DynamicResource MaxButtonStyle}"/>
                        <!--关闭按钮-->
                        <Button x:Name="btnClose" Content="M" Margin="2,2,2,2" Style="{DynamicResource CloseButtonStyle}"/>
                    </StackPanel>
                </Grid>


            </Border>
            <Border Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    Width="Auto"
                    Height="Auto"
                    DockPanel.Dock="Top"
                    CornerRadius="0,0,4,4">
                <AdornerDecorator>
                    <ContentPresenter />
                </AdornerDecorator>
            </Border>
        </DockPanel>
    </ControlTemplate>
    <Style x:Key="BaseWindowStyle"
           TargetType="{x:Type Window}">
        <Setter Property="Foreground"
                Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
        <Setter Property="Background"
                Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
        <Setter Property="Template" Value="{StaticResource BaseWindowControlTemplate}"/>
            
        <Setter Property="AllowsTransparency"
                Value="True" />
        <Setter Property="WindowStyle"
                Value="None" />
        <Setter Property="BorderBrush"
                Value="#FF7097D0" />
        <Setter Property="BorderThickness"
                Value="4,4,4,4" />
        <Style.Triggers>
            <Trigger Property="ResizeMode"
                     Value="CanResizeWithGrip">
                <Setter Property="Template"
                        Value="{StaticResource WindowTemplateKey}" />
            </Trigger>
        </Style.Triggers>
    </Style>
    <!--最小化按钮-->
    <Style x:Key="MinButtonStyle" TargetType="{x:Type Button}">

        <Setter Property="Foreground" Value="Black"/>
        <!--修改模板属性-->
        <Setter Property="Template">
            <Setter.Value>
                <!--控件模板-->
                <ControlTemplate TargetType="Button">
                    <!--背景色-->
                    <Border x:Name="back" Opacity="0.8" CornerRadius="0" BorderBrush="#FFCDA05F" Background="#FFFFE9C9" BorderThickness="1" Margin="1" Padding="2,0,0,0">
                        <!--按钮内容-->
                        <Path x:Name="cp" Width="12" Height="12"  
                                  Stroke="#FFCEA15F"  
                                  StrokeThickness="3" Fill="Black">

                            <Path.Data>
                                <PathGeometry Figures="M 0,6 H 6,6 " />
                            </Path.Data>
                        </Path>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">

                            <Setter Property="Background" TargetName="back" Value="#FFD4BD9B"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="Background" TargetName="back" Value="#FFCDA05F"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--最大化按钮-->
    <Style x:Key="MaxButtonStyle" TargetType="{x:Type Button}">

        <Setter Property="Foreground" Value="Black"/>
        <!--修改模板属性-->
        <Setter Property="Template">
            <Setter.Value>
                <!--控件模板-->
                <ControlTemplate TargetType="Button">
                    <!--背景色-->
                    <Border x:Name="back" Opacity="0.8" CornerRadius="0" BorderBrush="#FFCDA05F" Background="#FFFFE9C9" BorderThickness="1" Margin="1" Padding="2,0,0,0">
                        <!--按钮内容-->
                        <Path x:Name="cp" Width="12" Height="12"  
                                  Stroke="#FFCEA15F"  
                                  StrokeThickness="3" >

                            <Path.Data>
                                <PathGeometry Figures="M 0,0 L 0,12 12,12 12,0 0,0" />
                            </Path.Data>
                        </Path>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">

                            <Setter Property="Background" TargetName="back" Value="#FFD4BD9B"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="Background" TargetName="back" Value="#FFCDA05F"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <!--关闭按钮-->
    <Style x:Key="CloseButtonStyle" TargetType="{x:Type Button}">

        <Setter Property="Foreground" Value="Black"/>
        <!--修改模板属性-->
        <Setter Property="Template">
            <Setter.Value>
                <!--控件模板-->
                <ControlTemplate TargetType="Button">
                    <!--背景色-->
                    <Border x:Name="back" Opacity="0.8" CornerRadius="0" BorderBrush="#FFCDA05F" Background="#FFFFE9C9" BorderThickness="1" Margin="1" Padding="2,0,0,0">
                        <!--按钮内容-->
                        <Path x:Name="cp" Width="12" Height="12"  
                                  Stroke="#FFCEA15F"  
                                  StrokeThickness="3" >

                            <Path.Data>
                                <PathGeometry Figures="M 0,0 L 12,12 M 0,12 L 12,0" />
                            </Path.Data>
                        </Path>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">

                            <Setter Property="Background" TargetName="back" Value="#FFD4BD9B"/>
                        </Trigger>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="Background" TargetName="back" Value="#FFCDA05F"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>




</ResourceDictionary>

2、引用该模板文件。资源文件建立后,我们需要在程序中引用这个文件,打开APP.XAML,将引用的BaseWindowStyle添加进去:

<Application
             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" mc:Ignorable="d" x:Class="MyFirst.App"
             StartupUri="MainWindow.xaml">
    <Application.Resources>

        <ResourceDictionary Source="BaseWindowStyle.xaml">

        </ResourceDictionary>

    </Application.Resources>
</Application>

3、建立BaseWindow类,实现窗口点击,拖动等事件。在工程上点击右键“添加”->“类”->输入”BaseWindow.cs“

该类继承自Window,然后要载入模板文件,在模板文件中获取最小化、最大化等按钮,然后将这些按钮的点击事件和窗口绑定起来,实现窗口的响应:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;


namespace MyFirst
{
    public class BaseWindow : Window
    {
        public BaseWindow()
        {
            InitializeStyle();
            this.Loaded += delegate
            {
                InitializeEvent();
            };
        }

        private void InitializeEvent()
        {
            ControlTemplate baseWindowTemplate = (ControlTemplate)App.Current.Resources["BaseWindowControlTemplate"];

            Button minBtn = (Button)baseWindowTemplate.FindName("btnMin", this);
            minBtn.Click += delegate
            {
           
                this.WindowState = WindowState.Minimized;
            };

            Button maxBtn = (Button)baseWindowTemplate.FindName("btnMax", this);
            maxBtn.Click += delegate
            {
               
                this.WindowState = (this.WindowState == WindowState.Normal ? WindowState.Maximized : WindowState.Normal);
            };

            Button closeBtn = (Button)baseWindowTemplate.FindName("btnClose", this);
            closeBtn.Click += delegate
            {
                this.Close();
            };

            Border borderTitle = (Border)baseWindowTemplate.FindName("borderTitle", this);
            borderTitle.MouseMove += delegate(object sender, MouseEventArgs e)
            {
                if (e.LeftButton == MouseButtonState.Pressed)
                {
                    this.DragMove();
                }
            };
            borderTitle.MouseLeftButtonDown += delegate(object sender, MouseButtonEventArgs e)
            {
                if (e.ClickCount >= 2)
                {
                    maxBtn.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
                }
            };
        }


        private void InitializeStyle()
        {
            this.Style = (Style)App.Current.Resources["BaseWindowStyle"];
        }
    }
}

4,其它窗口类继承自BaseWindow:

public partial class Login : BaseWindow

5,其它窗口的风格指向BaseWindowStyle。

这里要注意一点Winodow的风格可不是直接 Style=”BaseWindowStyle” 那么简单,可以看看Login.xaml的代码:

<src:BaseWindow x:Class="MyFirst.Login"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:src="clr-namespace:MyFirst"
        Title="Login" Height="300" Width="300" Loaded="Window_Loaded"  WindowStartupLocation="CenterScreen">
    

</src:BaseWindow>

经过这么多步,我们终于实现了凡是继承自BaseWindow的窗口,都有统一的风格了!

WPF窗口继承

当然,如上的窗口还不是那么漂亮完美,但是相信你有办法把它做的美美的!

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

3条回应:“WPF窗口继承实现统一风格的自定义窗口”

  1. 功能医学说道:

    完全是看不懂的存在,算是打个酱油吧!

  2. vipc说道:

    地标金融P2P理财平台:http://www.dib66.com

发表评论

电子邮件地址不会被公开。 必填项已用*标注