接上一篇的通用窗体模板,这个模板是重写窗体样式的自定义模板,与上篇不一样的是它将窗体的一些基本功能所有清空(放大、缩小、关闭按钮,窗体双击放大缩小,窗体可拖拉大小,标题和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
注意代码中的标签或样式名称问题,可能会有没有统一的部分,使用时本身排查一下。