WPF通用窗体模板【2】

接上一篇的通用窗体模板,这个模板是重写窗体样式的自定义模板,与上篇不一样的是它将窗体的一些基本功能所有清空(放大、缩小、关闭按钮,窗体双击放大缩小,窗体可拖拉大小,标题和logo等)。咱们须要重写函数来实现这些功能。express

首先是新建窗体文件window.xaml,为什么不用资源字典文件呢?由于咱们须要写函数因此须要cs文件,而窗体文件新建后会自动生成window.xaml.cs,只需将window标签修改成ResourceDictionary便可。app

cs文件中修改:函数

而后开始写窗体样式,在xaml中添加:ui

<!-- 菜单按钮组模板 -->
    <Style x:Key="WindowCenterMenuBtn" TargetType="Button">
        <Setter Property="Foreground" Value="White"></Setter>
        <Setter Property="Opacity" Value="0.2"></Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Button">
                    <TextBlock FontSize="25" Text="{TemplateBinding Content}" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Opacity" Value="1.0"></Setter>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
 <!-- 通用窗口模板-标题居中 -->
    <ControlTemplate x:Key="WindowCenterTemplate" TargetType="Window">
        <Border x:Name="WindowCenterFrame" Margin="0" CornerRadius="0" BorderThickness="1" BorderBrush="DodgerBlue"  Background="#FFFFFF" MouseLeftButtonDown="CustomWindow_MouseLeftButtonDown" >
            <Border.Effect>
                <DropShadowEffect BlurRadius="3" RenderingBias="Performance" ShadowDepth="0" Opacity="1"/>
            </Border.Effect>
            <Grid >
                <Grid.RowDefinitions>
                    <RowDefinition Height="30"></RowDefinition>
                    <RowDefinition Height="*"></RowDefinition>
                </Grid.RowDefinitions>
                <Border Grid.Row="0">
                    <Border.Background>
                        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0" Opacity="0.6">
                            <GradientStop Color="#FFFBFBFC" Offset="1"/>
                            <GradientStop Color="#FFF3F7FB" Offset="0.021"/>
                        </LinearGradientBrush>
                    </Border.Background>
                    <Grid MouseDown="CustomWindow_MouseDoubleDown">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="1*"/>
                        <ColumnDefinition Width="120"/>
                    </Grid.ColumnDefinitions>
                    <StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Bottom" HorizontalAlignment="Center" Margin="60,0,0,0">
                        <Button   Width="22"  HorizontalAlignment="Center" Style="{StaticResource {x:Static ToolBar.ButtonStyleKey}}"
                                WindowChrome.IsHitTestVisibleInChrome="True"  
                                Command="{x:Static SystemCommands.ShowSystemMenuCommand}"
                                CommandParameter="{Binding ElementName=_MainWindow}">
                            <!-- Make sure there is a resource with name Icon in MainWindow -->
                            <Image  
                                    Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon}"
                                    WindowChrome.IsHitTestVisibleInChrome="True"/>
                        </Button>
                        <TextBlock   VerticalAlignment="Center" Text="{Binding Title, RelativeSource={RelativeSource TemplatedParent}}"  FontSize="13"/>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Right" Margin="0,0,20,0" VerticalAlignment="Center">
                        <Button x:Name="MinBtn" Height="20" Width="30" Content="-" 
                                Style="{StaticResource ResourceKey=WindowCenterMenuBtn}" Click="CustomWindowBtnMinimized_Click" />
                        <Button x:Name="MaxBtn" Height="20" Width="30" Content="□" 
                                Style="{StaticResource ResourceKey=WindowCenterMenuBtn}" Click="CustomWindowBtnMaxNormal_Click" />
                        <Button x:Name="CloseBtn" Height="20" Width="30" Content="×" 
                                Style="{StaticResource ResourceKey=WindowCenterMenuBtn}" Click="CustomWindowBtnClose_Click" />
                    </StackPanel>
                </Grid>
                </Border>
                <Grid Grid.Row="1">
                    <AdornerDecorator>
                        <ContentPresenter></ContentPresenter>
                    </AdornerDecorator>
                </Grid>
            </Grid>
        </Border>
    </ControlTemplate>

    <!-- 通用窗口样式-标题居中 -->
    <Style x:Key="WindowCenterChrome" TargetType="Window">
        <Setter Property="AllowsTransparency" Value="True"></Setter>
        <Setter Property="Background" Value="Transparent"></Setter>
        <Setter Property="WindowStyle" Value="None"></Setter>
        <Setter Property="ResizeMode" Value="NoResize"></Setter>
        <Setter Property="Template" Value="{StaticResource WindowCenterTemplate}"></Setter>
    </Style>

接下来是功能函数,在cs文件中添加代码,实现窗口的放大、缩小、关闭、双击放大缩小、鼠标拖动窗口等。this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

using System.Windows.Input;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace Resource.Styles.Base
{
    public partial class CustomWindow : ResourceDictionary
    {
        public class Tools
        {
            //双击事件定时器
            private static DispatcherTimer _timer;
            //是否单击过一次
            private static bool _isFirst;

            static Tools()
            {
                _timer = new DispatcherTimer();
                _timer.Interval = new TimeSpan(0, 0, 0, 0, 400);
                _timer.Tick += new EventHandler(_timer_Tick);
            }

            /// <summary>
            /// 判断是否双击
            /// </summary>
            /// <returns></returns>
            public static bool IsDoubleClick()
            {
                if (!_isFirst)
                {
                    _isFirst = true;
                    _timer.Start();
                    return false;
                }
                else
                {
                    return true;
                }
            }

            //间隔时间
            private static void _timer_Tick(object sender, EventArgs e)
            {
                _isFirst = false;
                _timer.Stop();
            }
        }

        // 拖动
        private void CustomWindow_MouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            Window win = (Window) ((FrameworkElement) sender).TemplatedParent;
            if (e.LeftButton == MouseButtonState.Pressed)
            {
                win.DragMove();
            }

        }

        //双击放大缩小
        private void CustomWindow_MouseDoubleDown(object sender, MouseEventArgs e)
        {
            Window win = (Window) ((FrameworkElement) sender).TemplatedParent;
            if (Tools.IsDoubleClick())
            {
                win.WindowState = win.WindowState == WindowState.Maximized
                    ? WindowState.Normal
                    : WindowState.Maximized;
            }
        }

        // 关闭
        private void CustomWindowBtnClose_Click(object sender, RoutedEventArgs e)
        {
            Window win = (Window) ((FrameworkElement) sender).TemplatedParent;
            //提示是否要关闭
            if (MessageBox.Show("肯定要退出系统?", "提示", MessageBoxButton.YesNo, MessageBoxImage.Question) ==
               MessageBoxResult.Yes)
            {
                System.Windows.Application.Current.Shutdown();
            }
        }

        // 最小化
        private void CustomWindowBtnMinimized_Click(object sender, RoutedEventArgs e)
        {
            Window win = (Window) ((FrameworkElement) sender).TemplatedParent;
            win.WindowState = WindowState.Minimized;
        }

        // 最大化、还原
        private void CustomWindowBtnMaxNormal_Click(object sender, RoutedEventArgs e)
        {
            Window win = (Window) ((FrameworkElement) sender).TemplatedParent;
            if (win.WindowState == WindowState.Maximized)
            {
                win.WindowState = WindowState.Normal;
            }
            else
            {
                // 不覆盖任务栏
                win.MaxWidth = SystemParameters.WorkArea.Width;
                win.MaxHeight = SystemParameters.WorkArea.Height;
                win.WindowState = WindowState.Maximized;
            }
        }
    }
}

最后在你要应用自定义样式的window窗体中添加引用:spa

<Window x:Class="EGIS.Main.UI.OPWindow"
        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"
        Style="{DynamicResource WindowCenterChrome}" 
        mc:Ignorable="d" WindowStartupLocation="CenterScreen"
				Loaded="OPWindow_Loaded" >
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="pack://application:,,,/EGIS.Resource;component/Resource/Generic.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

在这个窗体的cs文件中的OPWindow_Loaded函数中添加以下语句(实现页面加载全屏不遮挡任务栏):code

private void OPWindow_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                //使页面全屏化但不遮挡任务栏
                this.MaxWidth = SystemParameters.WorkArea.Width;
                this.MaxHeight = SystemParameters.WorkArea.Height;
                this.WindowState = WindowState.Maximized;
        }
            catch (Exception ex)
            {
               LogService.WriteExceptionLog(ex, "");
            }
            
        }

还有一个窗体事件为鼠标拖动改变窗口大小,这个查询了网上的一些方法,最终用下面的代码实现:component

#region 重写页面,鼠标左键拖动改变窗口大小
        #region 这一部分是四个边加上四个角
        public enum ResizeDirection
        {
            Left = 1,
            Right = 2,
            Top = 3,
            TopLeft = 4,
            TopRight = 5,
            Bottom = 6,
            BottomLeft = 7,
            BottomRight = 8,
        }
        #endregion

        #region 用于改变窗体大小
        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);

        private void ResizeWindow(ResizeDirection direction)
        {
            SendMessage(hs.Handle, WM_SYSCOMMAND, (IntPtr)(61440 + direction), IntPtr.Zero);
        }
        #endregion

        #region 为元素注册事件
        private void InitializeEvent()
        {
            //获取当前窗口调用的style样式
            Style temStyle = this.Resources["CustomWindowChrome"] as Style;
            if (temStyle!=null)
            {
                Setter temSetter = null;
                foreach (Setter item in temStyle.Setters)
                {
                    if (item.Value == Template)
                        temSetter = item;
                }

                ControlTemplate baseWindowTemplate = (ControlTemplate)temSetter.Value;
                Border borderClip = (Border)baseWindowTemplate.FindName("CustomWindowFrame", this);

                borderClip.MouseMove += delegate
                {
                    DisplayResizeCursor(null, null);
                };

                borderClip.PreviewMouseDown += delegate
                {
                    Resize(null, null);
                };

                borderClip.MouseLeftButtonDown += delegate
                {
                    DragMove();
                };

                this.PreviewMouseMove += delegate
                {
                    ResetCursor(null, null);
                };
            }
            
        }
        #endregion

        #region 重写的DragMove,以便解决利用系统自带的DragMove出现Exception的状况
        public new void DragMove()
        {
            if (this.WindowState == WindowState.Normal)
            {
                SendMessage(hs.Handle, WM_SYSCOMMAND, (IntPtr)0xf012, IntPtr.Zero);
                SendMessage(hs.Handle, WM_LBUTTONUP, IntPtr.Zero, IntPtr.Zero);
            }
        }
        #endregion

        #region 显示拖拉鼠标形状
        private void DisplayResizeCursor(object sender, MouseEventArgs e)
        {
            Point pos = Mouse.GetPosition(this);
            double x = pos.X;
            double y = pos.Y;
            double w = this.ActualWidth;  //注意这个地方使用ActualWidth,才可以实时显示宽度变化
            double h = this.ActualHeight;

            if (x <= relativeClip & y <= relativeClip) // left top
            {
                this.Cursor = Cursors.SizeNWSE;
            }
            if (x >= w - relativeClip & y <= relativeClip) //right top
            {
                this.Cursor = Cursors.SizeNESW;
            }

            if (x >= w - relativeClip & y >= h - relativeClip) //bottom right
            {
                this.Cursor = Cursors.SizeNWSE;
            }

            if (x <= relativeClip & y >= h - relativeClip)  // bottom left
            {
                this.Cursor = Cursors.SizeNESW;
            }

            if ((x >= relativeClip & x <= w - relativeClip) & y <= relativeClip) //top
            {
                this.Cursor = Cursors.SizeNS;
            }

            if (x >= w - relativeClip & (y >= relativeClip & y <= h - relativeClip)) //right
            {
                this.Cursor = Cursors.SizeWE;
            }

            if ((x >= relativeClip & x <= w - relativeClip) & y > h - relativeClip) //bottom
            {
                this.Cursor = Cursors.SizeNS;
            }

            if (x <= relativeClip & (y <= h - relativeClip & y >= relativeClip)) //left
            {
                this.Cursor = Cursors.SizeWE;
            }
        }
        #endregion

        #region  还原鼠标形状
        private void ResetCursor(object sender, MouseEventArgs e)
        {
            if (Mouse.LeftButton != MouseButtonState.Pressed)
            {
                this.Cursor = Cursors.Arrow;
            }
        }
        #endregion

        #region 判断区域,改变窗体大小
        private void Resize(object sender, MouseButtonEventArgs e)
        {
            Point pos = Mouse.GetPosition(this);
            double x = pos.X;
            double y = pos.Y;
            double w = this.ActualWidth;
            double h = this.ActualHeight;

            if (x <= relativeClip & y <= relativeClip) // left top
            {
                this.Cursor = Cursors.SizeNWSE;
                ResizeWindow(ResizeDirection.TopLeft);
            }
            if (x >= w - relativeClip & y <= relativeClip) //right top
            {
                this.Cursor = Cursors.SizeNESW;
                ResizeWindow(ResizeDirection.TopRight);
            }

            if (x >= w - relativeClip & y >= h - relativeClip) //bottom right
            {
                this.Cursor = Cursors.SizeNWSE;
                ResizeWindow(ResizeDirection.BottomRight);
            }

            if (x <= relativeClip & y >= h - relativeClip)  // bottom left
            {
                this.Cursor = Cursors.SizeNESW;
                ResizeWindow(ResizeDirection.BottomLeft);
            }

            if ((x >= relativeClip & x <= w - relativeClip) & y <= relativeClip) //top
            {
                this.Cursor = Cursors.SizeNS;
                ResizeWindow(ResizeDirection.Top);
            }

            if (x >= w - relativeClip & (y >= relativeClip & y <= h - relativeClip)) //right
            {
                this.Cursor = Cursors.SizeWE;
                ResizeWindow(ResizeDirection.Right);
            }

            if ((x >= relativeClip & x <= w - relativeClip) & y > h - relativeClip) //bottom
            {
                this.Cursor = Cursors.SizeNS;
                ResizeWindow(ResizeDirection.Bottom);
            }

            if (x <= relativeClip & (y <= h - relativeClip & y >= relativeClip)) //left
            {
                this.Cursor = Cursors.SizeWE;
                ResizeWindow(ResizeDirection.Left);
            }
        }
        #endregion

        #endregion

代码中注意修改一下,将CustomWindowChrome改成通用窗体的名称WindowCenterChrome。CustomWindowFrame修改成WindowCenterFrame。orm

到此,一个彻底重写的自定义样式就完成了,还有一点和上篇的通用窗体样式同样,会与WindowsFormsHost控件有冲突。xml

注意代码中的标签或样式名称问题,可能会有没有统一的部分,使用时本身排查一下。

相关文章
相关标签/搜索