• WPF学习 - 自定义窗体(一)


    .Net默认的窗体样式只有四种:None、SingleBorderWindow、ThreeDBorderWindow、ToolWindow,都比较“丑”。而很多时候,我们希望自定义窗体,比如,无边框,有阴影,或者有模糊效果等。

    在WPF中,要实现自定义窗体比较简单,主要有两种方法:

    1)使用WindowChrome;

    2)使用WindowStyle = “None”。

    一、使用WindowChrome。

      WindowChrome,可以翻译为:窗体装饰条,官方文档中的定义是:表示一个对象,它描述窗口非工作区区域的自定义。(官方链接:WindowChrome 类 (System.Windows.Shell) | Microsoft Learn

      在官方的解释中,窗口由两部分构成:客户区域,非客户区域。

    图中,Client Area表示客户区域;其他的部分,统称为非客户区域

     

    那么WindowChrome的作用是,将客户区域扩展至整个窗体(遮住了非客户区),同时提供部分标准窗体的功能。如下所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    "ControlTest.WindowNone"
            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:ControlTest"
            mc:Ignorable="d"
            Title="WindowNone" Height="450" Width="800">
         
        
        
            
        
         
        
            
                "项目"/>
                "代码"/>
            
        

       备注:这里的边框,是TabControl的边框,不是窗体的边框。

     

     用上WindowChrome后,会惊奇的发现:在原标题栏的位置,可以用鼠标拖动了;在窗体的四周,可以调整窗体的大小了!Amazing!

    但同时,又出现了一个新的问题:窗体中的所以内容,都不能交互(鼠标点击,用户输入)了。

    这是为什么呢?可以这样理解。WindowChrome就像一个图层,它将窗体整个覆盖住了。因此窗体上的内容,自然就操作不了。那要如何才能点击呢?

    这需要给交互控件,添加WindowChrome的附件属性:IsHitTestVisibleInChrome。如下所示。

    1
    2
    3
    4
    5
    6
    7
        
        "True">
            "项目"/>
            "代码"/>
        

      如果你以为这样就万事大吉了,那只能说太天真了,微软的东西,哪有那么简单的呢??哈哈~ 

      如果真的按照这个代码,你会发现,又不能使用鼠标拖动窗体了。这是为什么呢?明明之前都可以,为何为控件添加了一个附加属性后,就不行了呢?

      问题肯定出在WindowChrome上。那么我们再来看看WindowChrome:

    图中有颜色的区域,实际上均为透明的看不见的。此处附上颜色则是为了方便解释。

     

    这个图就是WindowChrome的模型。其中Caption区域,表示标题栏,就是它,允许窗体被鼠标拖动。GlassFrameThickness就是Aero窗体的透明边框(Aero主体只在部分操作系统中支持)。ResizeBorderThickness就是调整窗体大小的边框的粗细,它提供了使用鼠标调整窗体大小的功能。而CornerRadius,则将窗体变成了圆角,它只有在GlassFrameThickness = 0 或者未启用Aero主体的窗口中才有效。。

    再回到上面的问题,为什么添加了附加属性,就不能用鼠标拖动窗体了呢?

    原因在于,TabControl进入了Caption区域。因为设置了附加属性(IsHitTestVisibleInChrome),表示鼠标可以“击穿”WindowChrome,那么自然就无法“点击”到Caption区域,自然就无法拖动窗体了。

    那么如果解决这个问题呢?以及如何添加按钮呢?答案是手动添加标题栏。哈哈~ 如下代码所示:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    Xaml代码:
     
    "ControlTest.WindowNone"
            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:ControlTest"
            mc:Ignorable="d"
            Title="WindowNone" Height="450" Width="800">
         
        
             
            "30" CornerRadius="20" GlassFrameThickness="0"/>
        
     
        "1">
            
                
                    "auto"/>
                    "*"/>
                
                "30" Background="YellowGreen">
                    
                        
                            
                        
                        "Horizontal" WindowChrome.IsHitTestVisibleInChrome="True">
                            
                            "Center" Margin="3,0" Text="{Binding Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
                        
     
                        "Horizontal" HorizontalAlignment="Right" WindowChrome.IsHitTestVisibleInChrome="True">
                            
                            
                            
                        
                    
                
                
                "1" WindowChrome.IsHitTestVisibleInChrome="True">
                    "项目"/>
                    "代码"/>
                
            
        
     
    C# 代码:
     
    public partial class WindowNone : Window
    {
        public WindowNone()
        {
            InitializeComponent();
        }
        // 最小化
        private void Btn_Min(object sender, RoutedEventArgs e)
        {
            this.WindowState = WindowState.Minimized;
        }
      // 最大化、还原
        private void Btn_Max(object sender, RoutedEventArgs e)
        {
            if(this.WindowState == WindowState.Normal)
            {
                this.WindowState = WindowState.Maximized;
            }
            else
            {
                this.WindowState = WindowState.Normal;
            }
        }
      // 关闭窗体
        private void Btn_Close(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }

     

    手动添加了标题栏之后,在标题栏上,你就可以放上任何你放的东西。。。。

     

    二、使用WindowStyle = "None"

    将窗体的WindowStyle属性设置为None后,窗体呈现这样:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    "ControlTest.NoneWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            mc:Ignorable="d"
            Title="NoneWindow" Height="450" Width="800"
            WindowStyle="None">
        
            
                "项目"/>
                "代码"/>
            
        

      

    这里,你会发现,窗体可以通过鼠标调整大小,但是不能用鼠标拖动。那解决的办法是什么呢?同样是手动设置一个标题栏: 

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    Xaml 代码:
    "ControlTest.NoneWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            mc:Ignorable="d"
            Title="NoneWindow" Height="450" Width="800"
            WindowStyle="None" BorderThickness="0" BorderBrush="Transparent">
        
            
                "auto"/>
                "*"/>
            
            "30" Background="YellowGreen"
                    MouseDown="TitleMove">
                
                    
                        
                    
                    "Horizontal" WindowChrome.IsHitTestVisibleInChrome="True">
                        
                        "Center" Margin="3,0" Text="{Binding Title, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}}"/>
                    
     
                    "Horizontal" HorizontalAlignment="Right" WindowChrome.IsHitTestVisibleInChrome="True">
                        
                        
                        
                    
                
            
            "1" Margin="10">
                "项目"/>
                "代码"/>
            
        
     
    C# 代码:
     
        public partial class NoneWindow : Window
        {
            public NoneWindow()
            {
                InitializeComponent();
            }
     
            // 窗体移动
            private void TitleMove(object sender, MouseButtonEventArgs e)
            {
                if (e.ChangedButton != MouseButton.Left) return;            // 非左键点击,退出
                if (e.ClickCount == 1)
                {
                    this.DragMove();                                        // 拖动窗体
                }
                else
                {
                    WindowMax();                                            // 双击时,最大化或者还原窗体
                }
            }
     
     
            // 最小化
            private void Btn_Min(object sender, RoutedEventArgs e)
            {
                this.WindowState = WindowState.Minimized;
            }
     
             
     
            // 关闭窗体
            private void Btn_Close(object sender, RoutedEventArgs e)
            {
                this.Close();
            }
     
            // 最大化、还原
            private void Btn_Max(object sender, RoutedEventArgs e)
            {
                WindowMax();
            }
     
            private void WindowMax()
            {
                if (this.WindowState == WindowState.Normal)
                {
                    this.WindowState = WindowState.Maximized;
                }
                else
                {
                    this.WindowState = WindowState.Normal;
                }
            }
     
             
        }

      

    这种方式下,会发现在窗体的“标题栏”上面,还有一点留白无法去除,同样窗体的边框也是无法去除的。这是为何呢?实际上顶部的留白、以及周变的“边框”,并不是边框。而是ResizeGrip(用于调整窗体大小的控件,它是Window)的样式。当设置Window的ResizeMode = “NoResize”时,这些留白、边框就消失不见了。

    此时,又出现了一个问题。没有了这些留白,我如何调整窗体的大小呢?

    答案是,可以使用Adorner。因为此处我也是抄了别人的代码,所以就不过多解释了,只把链接放上,各位看官自行查阅吧:https://blog.csdn.net/u013113678/article/details/121548138

     

    三、更多效果

    上文只提到了如果去掉边框,同时保留窗体的基本功能。但是窗体的效果似乎没有多么绚烂。那么下一篇文章,咱们就说说如果做效果....

  • 相关阅读:
    有意思的脑经急转弯API
    Linux学习-67-日志服务器设置和日志分析工具(logwatch)安装及使用
    KVM 教程
    基于VUE + Echarts 实现可视化数据大屏环保可视化
    VC6 MFC Dialog as apllication 编程
    java springboot儿童影楼管理系统
    从Spring迁移到Spring Boot
    小学生python游戏开发pygame5--title地图调用
    如何发布一个 TypeScript 编写的 npm 包
    microk8s 报错tls: failed to verify certificate: x509:
  • 原文地址:https://www.cnblogs.com/raynado/p/17677289.html