zoukankan      html  css  js  c++  java
  • WPF 使用WindowChrome自定义窗体 保留原生窗体特性

    本文大幅度借鉴dino.c大佬的文章

    https://www.cnblogs.com/dino623/p/uielements_of_window.html

    https://www.cnblogs.com/dino623/p/problems_of_WindowChrome.html

    https://www.cnblogs.com/dino623/p/custom_window_style_using_WindowChrome.html

    我在这里汇总一下,属于粘了就能用那种。在预设100,125,150,175DPI下最大化也能正常显示。

    不懂的地方可以阅读上面的文章

    说到原生窗体的特性都有什么 咱来做个对比 大家来感受下

    使用WindowChrome

    使用WindowStyle="None"

    使用WindowChrome的时候 无需设置就保留了原生阴影、拖拽、交互动画

    而使用WindowStyle="None"的话,会发现最大化的时候会覆盖任务栏。

    想要实现原生的样式就需要自己手写。

    这些功能可以实现吗?能实现。效果好吗? 不一定,像我这种WPF玩的不专业的人很难实现这些功能,啥玩意都得上网扒拉,对不对路还不一定,那百度上一人一种写法,这就很闹心。

    <Window x:Class="WpfApp1.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"
            mc:Ignorable="d"
            Title="MainWindow" SnapsToDevicePixels="True" StateChanged="Window_StateChanged" Loaded="Window_Loaded">
        <WindowChrome.WindowChrome>
            <WindowChrome UseAeroCaptionButtons="False" NonClientFrameEdges="None" CaptionHeight="40" />
        </WindowChrome.WindowChrome>
        <Grid x:Name="grdMain" Background="Transparent">
            <Grid.RowDefinitions>
                <RowDefinition Height="40"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid Grid.Row="0" Background="#C62F2F">
                <WrapPanel Orientation="Horizontal" WindowChrome.IsHitTestVisibleInChrome="True" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,10,0">
                    <Button x:Name="btnMin" Style="{DynamicResource MinButton}" Click="BtnMin_Click"/>
                    <Button x:Name="btnNorm" Style="{DynamicResource MaxButton}" Margin="3,0,0,0" Click="BtnNorm_Click"/>
                    <Button x:Name="btnClose" Style="{DynamicResource CloseButton}" Margin="3,0,0,0" Click="BtnClose_Click"/>
                </WrapPanel>
            </Grid>
            <Grid Grid.Row="1" Background="#FFFFFF">
                <Border BorderThickness="1" BorderBrush="#C62F2F"/>
            </Grid>
        </Grid>
    </Window>

    UseAeroCaptionButtons 表示是对 Windows Aero 标题按钮启用的命中测试是否可用,默认值为True。

    NonClientFrameEdges 获取或设置一个值,该值表示窗口框架边缘是否归客户端所有,默认值为None。

    CaptionHeight 表示窗体菜单栏高度,我这里设置跟Gird里第一行高度一致,代表自定义的菜单栏。

    注意下,我在放置按钮的WrapPanel容器中设置了 WindowChrome.IsHitTestVisibleInChrome,该值表示 WPF 命中测试在窗口非工作区中的元素是否可用,默认值为False。

    接下来是后台代码

    using System;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Input;
    
    namespace WpfApp1
    {
        /// <summary>
        /// MainWindow.xaml 的交互逻辑
        /// </summary>
        public partial class MainWindow : Window
        {
            int paddings = 0;
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                paddings = 4;
            }
    
            private void Window_StateChanged(object sender, EventArgs e)
            {
                if (WindowState == WindowState.Maximized)
                {
                    Thickness thickness = SystemParameters.WindowResizeBorderThickness;
                    grdMain.Margin = new Thickness(thickness.Left + paddings, thickness.Top + paddings, thickness.Right + paddings, thickness.Bottom + paddings);
                }
                else
                {
                    grdMain.Margin = new Thickness(0);
                }
            }
    
            private void BtnMin_Click(object sender, RoutedEventArgs e)
            {
                WindowState = WindowState.Minimized;
            }
    
            private void BtnClose_Click(object sender, RoutedEventArgs e)
            {
                Close();
            }
    
            private void BtnNorm_Click(object sender, RoutedEventArgs e)
            {
                if (WindowState == WindowState.Normal)
                {
                    btnNorm.Style = (Style)FindResource("NormButton");
                    WindowState = WindowState.Maximized;
                }
                else
                {
                    btnNorm.Style = (Style)FindResource("MaxButton");
                    WindowState = WindowState.Normal;
                }
            }
        }
    }

    这里的paddings我默认设置为4,这里需要借鉴下大佬的第一、二篇文章,里面很清晰的解释道为啥设置为4。

    完整看过第二篇文章的会发现无法直接获取SM_CXPADDEDBORDER的值。

    我查了官网文档user32.dll里面有函数可以取值。https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-getsystemmetrics

    [DllImport("user32.dll", CharSet = CharSet.Auto)]
    
    public static extern int GetSystemMetrics(int index);

    只不过按照这个取值来的话125往上的DPI最大化显示不正常,边框会比之前厚,咱就默认4就行。

  • 相关阅读:
    2013年发生云盘圈地大战的原因(1是因为流量成本降价,2是因为硬盘降价,3是免费是未来的商业模式)
    硬盘可以支持140万小时(也就是159年)的MTBF(硬盘只是一次性的投入)
    百度不愧为流量之王(空间的问题只是满足了用户之间的“虚荣”,而功能的完善才最终决定了事件的走向)
    唐太宗用人 不以一恶忘其善(使用每个人的特点去做事情)
    js模块化编程
    Flux
    安装配置gerrit
    redis
    Ruby
    演进式设计
  • 原文地址:https://www.cnblogs.com/xymfblogs/p/13589867.html
Copyright © 2011-2022 走看看