WPF 實現完全可控制的漂亮自定義窗口


在WPF界面開發中,有時候不想用系統的死板的窗口,想要來點新花樣,常會自定義窗口。

那么,先拋出問題,想搞出下面這樣的窗口,該咋整 ?

a

 

 下面看一個啥也沒設置過的普通窗口,這樣的窗口,我們只能控制客戶區,也就是白色部分,標題的棕色部分長啥樣,我們控制不了。

 

 

所以我們要做的就是把窗口的棕色部分,也整成我們想寫啥就寫啥。下面放上我實現的效果,源碼  https://files.cnblogs.com/files/CSSZBB/CustomWndow.rar

 下面娓娓道來,一個窗口大概需要實現的功能如下

 

 

太久遠的年代的做法我們就不討論了,

現在隨便一搜,應該有文章都會說用WindowChrome,如果沒有windowchrome,上述的所有功能都需要自己實現,光是拖動邊框改變大小這么一個,就夠寫半天的啦。

 

先說坑把,

1 主要就是最大化的邏輯,使用WindowChrome后最大化有點問題需要特殊處理,且受windowstyle="None"  ResizeMode="NoResize"  這些參數的影響,最大化的效果也不同,需要注意。

2 在 captionHeight 的范圍內的控件,需設置WindowChrome.IsHitTestVisibleInChrome="True" 這個附加屬性,

 

另外說一下windowstyle="None" 這個參數,按我目前試過的經驗來說,除非需要制作能透明的窗口,否則是不需要設置windowstyle="None" 的 ,windowstyle="None" 時,系統自帶的最大化,最小化,關閉 三個按鈕,都是沒有的,需要自己去實現。

 

 當你給窗口設置了WindowChrome后,

    <Window.Style>
        <Style TargetType="Window">
            <Setter Property="WindowChrome.WindowChrome">
                <Setter.Value>
                    <WindowChrome CornerRadius="0"
             CaptionHeight="30" GlassFrameThickness="-1" UseAeroCaptionButtons="True" NonClientFrameEdges="None" /> </Setter.Value> </Setter> </Style> </Window.Style>

  

先不改window的style的其他參數。看到棕色的部分沒有了,就是說設置了WindowChrome后,我們可控制的區域,擴展了本來不能控制的棕色頭部

 

 

那么,是否系統給我們生成的棕色部分,沒有了那?其他它還是在的,只是被我們的白色部分覆蓋了。這里修改一下window的Template 。可以看到它又露出來了

            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate  TargetType="Window">
                        <Grid  >
                            <Grid.RowDefinitions>
                                <RowDefinition Height="32"/>
                                <RowDefinition Height="*"/>
                            </Grid.RowDefinitions>
                            <Grid x:Name="Content_Panel" Grid.Row="1" Background="{TemplateBinding Background}">
                                <AdornerDecorator>
                                    <ContentPresenter/>
                                </AdornerDecorator>
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>

 上面的代碼中,我們給Window的模板,定義了一個32高度的行,這個行里啥也不放,也就是透明的。可以看到,系統給生成的最大化,最小化等按鈕它又出來了,但是標題,ICO等就沒有了。說明標題和ICON ,需要在Template中定義,它不是系統生成的。

 

 

那么,上面指出觀察到的這個情況,有何意義那?

意義可能就是,有時候,我們只是想在標題欄(棕色部分) 添加幾個控件,比如加個公司圖標啊啥的,而不想改變其它時,可以這樣做。這樣,可以給我們省下自己去重寫最大化,最小化,關閉按鈕的時間

 

 這里面忘記說了窗口重寫Style的一個不算坑的坑,在編碼階段,不管你怎么設置Style,標題部分都是不變的,我一度以為是自己寫的Style無效,一運行才發現是有效的

 

 

更多的時候,我們希望完全重寫棕色部分。如下是一個框架的Window給我們提供的所有功能(包括邊框拖動改變大小,按住標題區拖動改變位置),那么我們重寫Style Template后,需要自己實現哪些部分那?

 

據我的經驗,需要自己實現圖標,標題,最小化,最大化,關閉這5個部分,

在沒有WindowChrome的年代,重寫window是需要自己實現所有功能的,所以說windowchrome還是提供了一些方便的。

來看下它的屬性, 1 CaptionHeight 這個屬性,是控制標題區(棕色部分,設置windowchrome后它不顯示),接收鼠標響應的高度。  本來它現實的時候,這個部分右鍵,會彈出系統菜單,按住拖動,雙擊等都有響應的邏輯

 

 現在棕色部分雖然不顯示了,但是設置了CaptionHeight 后,相應高度的部分,仍然會對支持上述操作。

它也導致了一個問題,就是當你放上你自己寫的最大化,最小化,關閉按鈕時,你會發現點擊無效,點這些按鈕還是觸發的 點擊標題欄的事件。

這就牽扯出另外一個屬性

WindowChrome.IsHitTestVisibleInChrome="True"。給你自己寫的最大化,最小化,關閉按鈕時,加上這個附加屬性,他們就能響應鼠標了

 

 到此,自定義標題欄,應該沒啥問題了,你想加啥控件就加啥,完全自由。

 其他屬性影響不大

 

那么該說說里面的坑了,當你點擊最大化窗口時,你會發現它的最大化是有問題的。如下圖對比,最大化前,可以看到窗口里的3層的綠色邊框,最大化后,發現左右下都只能看到一層邊框了。且最大化等按鈕,也超出了屏幕導致沒顯示全。

如果你設置了windows 的屬性ResizeMode="NoResize",或者WindowStyle="None" 你會發現最大化后,它把任務欄也給占了,就想真正的全屏游戲一樣!!

 

 

 這里的原因想想也不難理解,最大化窗口,你自己實現最大化按鈕一般只用設置WindowState = WindowState.Maximized;(不管是直接設置屬性還是用系統命令)

而系統去做最大化這一步,其實是要很多步驟的,包括獲取屏幕大小,計算窗口邊框,調整窗口大小到屏幕大小(這里要去掉任務欄高度,去掉邊框寬度)等等,

那么當你通過windowchrome重寫了windowstyle改變了客戶區的大小,系統默認給你的窗口邊框邊框也變了,它如果還是按原來的處理方式最大化,應該是有問題的。

這里的更精確的原理我們猜也猜不明白,也不是我們能控制的。只要能根據現在的現象調整出對的結果就行了

 

我直接說結果就是最大化時,系統把整個界面多最大化了8。上下左右都是。所以我們設置一個觸發器,在最大化的時候,把我們自己定義的區域,縮小8就行了

 

 

完美!!

剩下的,就是把窗口做的漂亮點啦。開搞把!

 


免責聲明!

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



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