首页 > 其他分享 >WPF自定义Window

WPF自定义Window

时间:2024-04-12 17:12:08浏览次数:17  
标签:自定义 void object Window SystemCommands new WPF

前言

我们使用WPF开发客户端软件时,一般来讲都不会直接使用默认的Window样式,因为很难符合项目的风格,所以我们一般会自定义Window,一般有两种方式。WindowStyle=None和自定义Window,本文主要介绍第二种。

一、WindowStyle=None

WindowStyle="None"

将Window的整个边框就去掉了,好处是简单,缺点是需要自己实现剩下的内容,因为Window并不是一个普通的简单控件。

标题栏 需要自己添加,其次还要自己实现最小化、最大化、还原、拖动等操作,令我最不能接受的并不是这部分工作,而是当设置了 WindowStyle="None"后,最小化、最大化窗口没有了淡入打出效果了(不同的Windows系统有不同的效果),而是生硬的感觉,这是我最不能接受的。

二、自定义Window

1、新建自定义控件CustomWindow,继承自Window,默认继承的是Control,此操作会生成两个文件,

1是class CustomWidow,也就是CodeBehind,一些窗体逻辑操作在这里执行;
2是会在Themes文件夹下的Generic.xaml中自动添加CustomWindow的 Style资源

CustomWindow.cs代码如下

public class CustomWindow : Window
{
    public CustomWindow()
    {
        DefaultStyleKey = typeof(CustomWindow);
        CommandBindings.Add(new CommandBinding(SystemCommands.CloseWindowCommand, CloseWindow));
        CommandBindings.Add(new CommandBinding(SystemCommands.MaximizeWindowCommand, MaximizeWindow, CanResizeWindow));
        CommandBindings.Add(new CommandBinding(SystemCommands.MinimizeWindowCommand, MinimizeWindow, CanMinimizeWindow));
        CommandBindings.Add(new CommandBinding(SystemCommands.RestoreWindowCommand, RestoreWindow, CanResizeWindow));
        CommandBindings.Add(new CommandBinding(SystemCommands.ShowSystemMenuCommand, ShowSystemMenu));
    }

    public event Action CloseWindowEvent;

    //protected override void onm ouseLeftButtonDown(MouseButtonEventArgs e)
    //{
    //    base.OnMouseLeftButtonDown(e);
    //    if (e.ButtonState == MouseButtonState.Pressed)
    //        DragMove();
    //}

    protected override void OnContentRendered(EventArgs e)
    {
        base.OnContentRendered(e);
        if (SizeToContent == SizeToContent.WidthAndHeight)
            InvalidateMeasure();
    }

    private void CanResizeWindow(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = ResizeMode == ResizeMode.CanResize || ResizeMode == ResizeMode.CanResizeWithGrip;
    }

    private void CanMinimizeWindow(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = ResizeMode != ResizeMode.NoResize;
    }

    private void CloseWindow(object sender, ExecutedRoutedEventArgs e)
    {
        if (null != CloseWindowEvent)
        {
            CloseWindowEvent();
        }
        this.Close();
    }

    private void MaximizeWindow(object sender, ExecutedRoutedEventArgs e)
    {
        SystemCommands.MaximizeWindow(this);
    }

    private void MinimizeWindow(object sender, ExecutedRoutedEventArgs e)
    {
        SystemCommands.MinimizeWindow(this);
    }

    private void RestoreWindow(object sender, ExecutedRoutedEventArgs e)
    {
        SystemCommands.RestoreWindow(this);
    }

    private void ShowSystemMenu(object sender, ExecutedRoutedEventArgs e)
    {
        var element = e.OriginalSource as FrameworkElement;
        if (element == null)
            return;

        var point = WindowState == WindowState.Maximized ? new Point(0, element.ActualHeight)
            : new Point(Left + BorderThickness.Left, element.ActualHeight + Top + BorderThickness.Top);
        point = element.TransformToAncestor(this).Transform(point);
        SystemCommands.ShowSystemMenu(this, point);
    }
}

Generic.xaml中样式如下

注意更改自己实际项目中的命名空间,如下文中的TVS.Niuniu是我的测试项目

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TVS.Niuniu" xmlns:customWindow="clr-namespace:TVS.Niuniu">
    <DataTemplate x:Key="RestoreWhite">
        <Grid UseLayoutRounding="True">
            <Path Data="M1,3 L1,11 L9,11 L9,3 z M3,1 L3,2 L10,2 L10,9 L11,9 L11,1 z M2 ,0 L12,0 L12,10 L10,10 L10,12 L0,12 L0,2 L2 ,2 z"
                  Width="12" Height="12" UseLayoutRounding="True"
                  VerticalAlignment="Center" HorizontalAlignment="Center" Fill="White" />
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="CloseWhite">
        <Grid UseLayoutRounding="True">
            <Path Data="M1,0 L6,5 L11,0 L12,1 L7,6 L12,11 L11,12 L6,7 L1,12 L0,11 L5,6 L0,1 z"
                  Width="12" Height="12" UseLayoutRounding="True"
                  VerticalAlignment="Center" HorizontalAlignment="Center" Fill="White" />
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="MaximizeWhite">
        <Grid>
            <Path Data="M1,1  L1 ,11 L11,11 L11,1 z M0,0 L12,0 L12,12 L0,12 z"
                  Width="12" Height="12" UseLayoutRounding="True"
                  VerticalAlignment="Center" HorizontalAlignment="Center" Fill="White" />
        </Grid>
    </DataTemplate>

    <DataTemplate x:Key="MinimizeWhite">
        <Grid>
            <Path Data="M0,5 L12,5 L12,6 L0,6 z"
                  Width="12" Height="12" UseLayoutRounding="True"
                  VerticalAlignment="Center" HorizontalAlignment="Center" Fill="White" />
        </Grid>
    </DataTemplate>

    <Style x:Key="TitleBarButtonFocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle Margin="2" SnapsToDevicePixels="True" Stroke="Transparent"
                    	StrokeDashArray="1 2" StrokeThickness="1" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style x:Key="TitleBarButtonStyle"
           TargetType="{x:Type Button}">
        <Setter Property="Focusable" Value="False" />
        <Setter Property="Background" Value="#15181C" />
        <Setter Property="Width" Value="36" />
        <Setter Property="HorizontalContentAlignment" Value="Center" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Grid x:Name="LayoutRoot"
                          Background="Transparent">
                        <Border x:Name="ButtonBackground"
                                BorderBrush="Gray" BorderThickness="1"
                                Opacity="0" Height="30" Width="30"/>
                        <Border x:Name="ButtonBorder"
                                SnapsToDevicePixels="true">
                            <ContentPresenter 
                            x:Name="TitleBarButtonContentPresenter" Focusable="False"
                            HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            Margin="{TemplateBinding Padding}" RecognizesAccessKey="True"
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                        </Border>
                    </Grid>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Opacity" Value="1" TargetName="ButtonBackground" />
                        </Trigger>
                        <Trigger Property="IsPressed" Value="True">
                            <Setter Property="Opacity" Value="0.6" TargetName="ButtonBackground" />
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter TargetName="TitleBarButtonContentPresenter" Property="Opacity" Value=".5" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

    <Style TargetType="{x:Type customWindow:CustomWindow}">
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
        <Setter Property="Background" Value="#FFF1F1F1" />
        <Setter Property="BorderBrush" Value="#15181C" />
        <Setter Property="BorderThickness" Value="0" />
        <Setter Property="IsTabStop" Value="False" />
        <Setter Property="ResizeMode" Value="CanResizeWithGrip" />
        <Setter Property="UseLayoutRounding" Value="True" />
        <Setter Property="TextOptions.TextFormattingMode" Value="Display" />
        <Setter Property="WindowStyle" Value="SingleBorderWindow" />
        <Setter Property="WindowChrome.WindowChrome">
            <Setter.Value>
                <WindowChrome CornerRadius="0" GlassFrameThickness="1"
                              UseAeroCaptionButtons="False" NonClientFrameEdges="None" />
            </Setter.Value>
        </Setter>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type customWindow:CustomWindow}">
                    <Border x:Name="WindowBorder">
                        <Grid Background="#FF15181C">
                            <Border VerticalAlignment="Top" Height="40">
                                <Border.Background>
                                    <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
                                        <GradientStop Color="#2B313B" Offset="1"/>
                                        <GradientStop Color="#181B21" Offset="0"/>
                                    </LinearGradientBrush>
                                </Border.Background>
                            </Border>
                            <Grid x:Name="LayoutRoot" Margin="30,0,30,30" Background="{TemplateBinding Background}">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="*" />
                                </Grid.RowDefinitions>
                                <Grid x:Name="PART_WindowTitleGrid" Grid.Row="0" Height="40">
                                    <Grid.Background>
                                        <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
                                            <GradientStop Color="#2B313B" Offset="1"/>
                                            <GradientStop Color="#181B21" Offset="0"/>
                                        </LinearGradientBrush>
                                    </Grid.Background>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="auto" />
                                    </Grid.ColumnDefinitions>
                                    <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                                        <Button VerticalAlignment="Center"
                                            Margin="7,0,5,0" Content="{TemplateBinding Icon}"
                                            Height="{x:Static SystemParameters.SmallIconHeight}"
                                            Width="{x:Static SystemParameters.SmallIconWidth}"
                                            WindowChrome.IsHitTestVisibleInChrome="True"
                                            IsTabStop="False">
                                            <Button.Template>
                                                <ControlTemplate TargetType="{x:Type Button}">
                                                    <Image Source="{TemplateBinding Content}" />
                                                </ControlTemplate>
                                            </Button.Template>
                                            <!--<i:Interaction.Triggers>
                                            <i:EventTrigger EventName="Click">
                                                <i:InvokeCommandAction Command="{x:Static SystemCommands.ShowSystemMenuCommand}" />
                                            </i:EventTrigger>
                                            <i:EventTrigger EventName="MouseDoubleClick">
                                                <i:InvokeCommandAction Command="{x:Static SystemCommands.CloseWindowCommand}" />
                                            </i:EventTrigger>
                                        </i:Interaction.Triggers>-->
                                        </Button>
                                        <ContentControl IsTabStop="False" Foreground="White"
                                                    HorizontalAlignment="Center" VerticalAlignment="Center"
                                                    HorizontalContentAlignment="Center" 
                                                    FontSize="16" FontFamily="Arial-BoldMT"
                                                    Content="{TemplateBinding Title}" />
                                    </StackPanel>
                                    <StackPanel x:Name="WindowCommandButtonsStackPanel"
                                            Grid.Column="1"
                                            HorizontalAlignment="Right"
                                            VerticalAlignment="Stretch"
                                            Background="Transparent"
                                            Orientation="Horizontal"
                                            WindowChrome.IsHitTestVisibleInChrome="True"
                                            Margin="0,-1,-1,0">
                                        <Button x:Name="Minimize"
                                            ToolTip="Minimize"
                                            WindowChrome.IsHitTestVisibleInChrome="True"
                                            Command="{Binding Source={x:Static SystemCommands.MinimizeWindowCommand}}"
                                            ContentTemplate="{StaticResource MinimizeWhite}"
                                            Style="{StaticResource TitleBarButtonStyle}"
                                            IsTabStop="False" />
                                        <Grid Margin="1,0,1,0">
                                            <Button x:Name="Restore"
                                                ToolTip="Restore"
                                                WindowChrome.IsHitTestVisibleInChrome="True"
                                                Command="{Binding Source={x:Static SystemCommands.RestoreWindowCommand}}"
                                                ContentTemplate="{StaticResource RestoreWhite}"
                                                Style="{StaticResource TitleBarButtonStyle}"
                                                Visibility="Collapsed" IsTabStop="False" />
                                            <Button x:Name="Maximize" ToolTip="Maximize"
                                                WindowChrome.IsHitTestVisibleInChrome="True"
                                                Command="{Binding Source={x:Static SystemCommands.MaximizeWindowCommand}}"
                                                ContentTemplate="{StaticResource MaximizeWhite}"
                                                Style="{StaticResource TitleBarButtonStyle}"
                                                IsTabStop="False" />
                                        </Grid>
                                        <Button x:Name="Close"
                                            ToolTip="Close" Background="Red"
                                            WindowChrome.IsHitTestVisibleInChrome="True"
                                            Command="{Binding Source={x:Static SystemCommands.CloseWindowCommand}}"
                                            ContentTemplate="{StaticResource CloseWhite}"
                                            Style="{StaticResource TitleBarButtonStyle}"
                                            IsTabStop="False" />
                                    </StackPanel>
                                </Grid>
                                <AdornerDecorator Grid.Row="1" KeyboardNavigation.IsTabStop="False">
                                    <ContentControl Content="{TemplateBinding Content}" x:Name="MainContentPresenter"/>
                                </AdornerDecorator>
                                <ResizeGrip x:Name="ResizeGrip"
                                        HorizontalAlignment="Right" VerticalAlignment="Bottom"
                                        Grid.Row="1" IsTabStop="False" Visibility="Hidden"
                                        WindowChrome.ResizeGripDirection="BottomRight" />
                            </Grid>
                        </Grid>
                    </Border>

                    <ControlTemplate.Triggers>
                        <!--<Trigger Property="IsActive" Value="False">
                            <Setter Property="BorderBrush" Value="#FF6F7785" />
                        </Trigger>-->
                        <Trigger Property="WindowState" Value="Maximized">
                            <Setter TargetName="Maximize" Property="Visibility" Value="Collapsed" />
                            <Setter TargetName="Restore" Property="Visibility" Value="Visible" />
                            <Setter TargetName="LayoutRoot" Property="Margin" Value="7" />
                        </Trigger>
                        <Trigger Property="WindowState" Value="Normal">
                            <Setter TargetName="Maximize" Property="Visibility" Value="Visible" />
                            <Setter TargetName="Restore" Property="Visibility" Value="Collapsed" />
                        </Trigger>
                        <Trigger Property="ResizeMode" Value="NoResize">
                            <Setter TargetName="Minimize" Property="Visibility"  Value="Collapsed" />
                            <Setter TargetName="Maximize" Property="Visibility" Value="Collapsed" />
                            <Setter TargetName="Restore" Property="Visibility" Value="Collapsed" />
                        </Trigger>

                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="ResizeMode" Value="CanResizeWithGrip" />
                                <Condition Property="WindowState" Value="Normal" />
                            </MultiTrigger.Conditions>
                            <Setter TargetName="ResizeGrip" Property="Visibility"  Value="Visible" />
                        </MultiTrigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</ResourceDictionary>

三、使用

使用很简单,只需要将Window换成CustomWindow

<local:CustomWindow x:Class="TVS.Niuniu.MainWindow"
        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"
        xmlns:local="clr-namespace:TVS.Niuniu" xmlns:models="clr-namespace:TVS.Niuniu.Models"
        d:DataContext="{d:DesignInstance Type=local:MainViewModel}"
        mc:Ignorable="d" 
        Title="MainWindow" Height="450" Width="800" WindowState="Normal">
   
</local:CustomWindow>

四、总结

示例代码的样式如下

样式可以根据实际的需要自己进行更改,Demo只是抛砖引玉。
好处是什么?
还是开头所说的,这样实现得自定义Window,其针对窗体的操作,不会丢失Windows自带的效果,如窗口弹出、窗口隐藏的动画等,会很平滑,如果想自己实现这种效果是非常复杂且效果不好的。

标签:自定义,void,object,Window,SystemCommands,new,WPF
From: https://www.cnblogs.com/bigappleblog/p/18131645

相关文章

  • Windows 10 专业工作站版:Win10中最强大的版本?
    Windows10提供了多个版本,满足不同用户的需求。其中,Windows10专业工作站版作为面向专业用户的旗舰版本,在性能、功能和安全方面都拥有显著优势,堪称Win10家族中最强大的版本。强悍的硬件支持Windows10专业工作站版支持更高的硬件配置,包括:最多支持4个CPU,而其他版本最多仅......
  • windows和Linux下路径表示
    reference一、\(Windows\)下的路径表示由于\(DOS\)原因,过去的\(windows\)路径表示采用反斜杠\,而路径字符串由于反斜杠的转义字符,因此需要用双反斜杠\\。\(Windows\)的根据路为磁盘号,后面跟:path如今的\(Windows\)内核在处理路径时同时支持正斜杠和反斜杠。但有时候......
  • docker network之 自定义网络(重点,多容器时都是使用这个)
    原来的默认使用bridge模式,创建好容器以后,2个容器使用ip地址去ping对方的ip是ok的,但是按照容器的服务名字取ping就失败: 我们知道容器在重启后,ip是可能变化的。所以那总不可能按照ip去访问吧,最好是按照服务名去访问,那怎么处理呢,请看下方:dockernetworklsdockernetworkcrea......
  • SpringBoot starter 原理及如何自定义 starter
     前言项目的开发要求是不断进化的,而随着时间以及技术的推移,在项目中除了基本的编程语言外,还需要进行大量的应用服务整合。例如,在项目中使用MySQL数据库进行持久化存储,同时会利用Redis作为缓存存储,以及使用RocketMQ实现异构系统整合服务等。但在早先使用Spring开发的......
  • Window10家庭版自动更新关闭方法
    win10的自动更新怎样关闭?分享给你三种方法! win10的自动更新怎样关闭?Win10系统总是自动更新,但是每次更新都会遇到各种问题,例如电脑总是自动重启、升级补丁占用系统盘空间、升级补丁冲突导致蓝屏、升级补丁异常导致打印机无法工作等等,那么你知道有哪些关闭win10自动更新的方法......
  • WPF 项目开发
    1、WPF文件管理助手1.1、文件比较1.2、文件差异1.3、文件上传下载2、WPF数据库同步助手2.1、数据表对比2.2、数据同步3、WPF视频录屏软件3.1、屏幕录屏3.2、区域录屏3.2、应用录屏3.3、录制GIF4、WPF软件自动升级器4.1、服务端4.2、客户端5、WPF软件授权码 6、WPFUI7、W......
  • windows端口转发
    windows端口转发windows提供端口转发功能,命令netshinterfaceportproxyhelp命令打印帮助信息netshinterfaceportproxyshowallshow命令showall-显示所有端口代理参数。showv4tov4-显示IPv4代理连接到另一个IPv4端口的参数。showv4tov6-......
  • kubectl windows安装
     kubectlwindows安装在Windows上安装kubectl通常涉及以下步骤:下载kubectl可执行文件。将kubectl可执行文件放置在系统路径中。以下是在Windows上安装kubectl的步骤: 访问KubernetesGitHub发布页面:https://github.com/kubernetes/kubernetes/blob/......
  • 界面控件DevExpress WinForms/WPF v23.2 - 富文本编辑器支持内容控件
    众所周知内容控件是交互式UI元素(文本字段、下拉列表、日期选择器),用于在屏幕上输入和管理信息。内容控件通常在模板/表单中使用,以标准化文档格式和简化数据输入。DevExpress文字处理产品库(WordProcessingDocumentAPI、WinForm和WPF富文本编辑器)附带了内容控制支持(v23.2+)。具......
  • windows MySQL报错Packet for query is too large问题解决
    1、报错Cause:com.mysql.cj.jdbc.exceptions.PacketTooBigException:Packetforqueryistoolarge(11,792,709>4,194,304).Youcanchangethisvalueontheserverbysettingthe'max_allowed_packet'variable.出现问题的原因:批量插入数据量过大MySQL根据配置......