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就行。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM