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

注意代碼中的標籤或樣式名稱問題,可能會有沒有統一的部分,使用時本身排查一下。

相關文章
相關標籤/搜索