1. 程式人生 > >自定義WPF 視窗樣式

自定義WPF 視窗樣式

原文: 自定義WPF 視窗樣式

自定義 Window

在客戶端程式中,經常需要用到自定義一個

Window ,大部分是為了好看吧。做了很多研究和實踐之後,覺得需要把這個過程寫下來,以供查閱。

WPF 提供的豐富的功能使得自定義 Window 變得簡單,但是也不是一個簡單的 Style 就能做到的事情。雖然 WPF 中的控制元件是 Lookless 的,但是 Window 類有他自己的特殊之處,做個簡單的實驗就能看出,對於普通的 WPF 控制元件,用 XamlWriter.Write 方法就能將某個型別物件的模板輸出出來,這樣就可以看到該控制元件的內部構造。但是如果輸出 Window 物件的預設模板,就會發現模板非常簡單,其中並沒有包含標題欄以及最大化最小化按鈕的定義,具體的實現不得而知,但是至少說明 Window 的預設 Style 不是按照 WPF 的規範來實現的。

 

為了實現任意風格的 Window 就需要重寫 Window 的預設模板,第一步要做的就是建立 Window 的一個派生類,並建立自定義 Style ,然後重寫 DefaultStyleKey 屬性讓 WPF 引擎來將樣式和 Window 的派生類裝載到一起。具體做法如下:

1.         建立一個 WPF Application 專案

2.         在專案中新增 Themes 資料夾,並在該資料夾下新增名稱為 Generic.xaml ResourceDictionary 。該資料夾和檔案的名稱和位置都是固定的,也就是說必須這麼做才能讓 WPF 引擎讓自定義控制元件和預設 Style 協同工作,因為微軟對此進行了硬編碼。

3.         建立自定義視窗類為 HeaderedWindow ,為什麼定義為 HeaderedWindow 呢?因為我覺得 Window 物件更像是一個 HeaderedContentControl 而不是一個 ContentControl ,因為它的標題欄更像是一個 Header ,而不僅僅是為了顯示圖示和標題! HeaderedWindow 類的定義如下:

 

public class HeaderedWindow : Window

{

static HeaderedWindow()

    {

      DefaultStyleKeyProperty.OverrideMetadata(typeof (HeaderedWindow ), new FrameworkPropertyMetadata (typeof (HeaderedWindow )));     

    }

}

 

4.         Generic.xaml 檔案中新增 HeaderedWindow 的預設樣式,如下:

< Style TargetType ="{ x : Type l : HeaderedWindow }">

    < Setter Property ="WindowStyle" Value ="None"/>

    < Setter Property ="ResizeMode" Value ="NoResize"/>

    < Setter Property ="Background" Value ="Gray"/>

    < Setter Property ="BorderBrush" Value ="#FF5A3D1C"/>

    < Setter Property ="BorderThickness" Value ="1"/>

    < Setter Property ="MinWidth" Value ="90"/>

    < Setter Property ="MinHeight" Value ="33"/>

    < Setter Property ="VerticalContentAlignment" Value ="Stretch"/>

    < Setter Property ="HorizontalContentAlignment" Value ="Stretch"/>

  </ Style >

最重要的兩個屬性是 WindowStyle ResizeMode ,將 WindowStyle 屬性設定為 None 將會去除預設的標題欄,將 ResizeMode 設定為 NoResize 將會去除 Window 邊框,該邊框在 Window 7 比較難看,不過卻有他的作用, 就是用來調整視窗大小,我們把它去掉了,就意味著我們需要自己來編寫調整視窗大小的程式碼了。

5.         測試一下這個 HeaderedWindow 吧,編寫如下測試程式碼:

 

< local : HeaderedWindow x : Class ="CustomWindowDemo.MainWindow"

         xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

         xmlns : x ="http://schemas.microsoft.com/winfx/2006/xaml"

         xmlns : local ="clr-namespace:CustomWindowDemo"

         Title ="MainWindow" Height ="350" Width ="525">

    < Grid >

       

    </ Grid >

</ local : HeaderedWindow >

後置程式碼類必須要從 HeaderedWindow 繼承才行。執行程式發現視窗黑乎乎一片。這是因為我們還沒有重寫 Window ControlTemplate 的緣故。

6.         一個視窗應該有如下基本要素

a)         圖示,就是 Icon 屬性,自定義視窗應該有將其顯示出來的能力

b)         標題,就是 Title 屬性,自定視窗應該將其顯示在標題欄中

c)         最大化,最小化,關閉按鈕

d)         為了美觀, Window 的邊框應該定義出來。但是當視窗最大化的時候應該隱藏邊框,擴大視窗的使用面積,這也是 Windows 下視窗的標準行為。

e)         八個方向的 Resizer 應該定義出來,這些 Resize 其實就是一些透明的 Thumb 控制元件,用來支援拖動事件,並改變視窗的定位和高寬。

對於 HeaderedWindow 還有幾個擴充套件要素需要提供:

a)         自定義 Header 屬性,使用者可以重新定義 Window Header ,在這裡我們將 Window Icon Title 定義為他的預設 Header ,所以有一個 ShowDefaultHeader 屬性用來控制預設 Header 的可見性。 Header 屬性是一個 Object 物件,其用法和 HeaderedContentControl 控制元件的 Header 幾乎一模一樣。

b)         ShowResizeGrip 屬性,用來控制是否在右下角顯示一個抓手模樣的圖形,用來指示用此處可以拖動,當然不顯示也可以調整視窗大小,不過顯示這個抓手增加了易用性。

c)         CanResize 屬性,由於我們在樣式中將視窗設定 ResizeMode NoResize ,所以需要提供一個額外的屬性用來設定當前視窗是否可以調整大小。當 CanResize False 的時候,所有可以調整視窗大小的控制元件將被隱藏。

d)         最後一個比較有意思的屬性就是 IsFullScreenMaximize ,當該屬性設定為 True 的時候,那麼當最大化的時候,視窗將把工作列覆蓋住。是真正意義上的“最大化”了。

7.           如果想製作不規則形狀的視窗,需要將 AllowTransparency 屬性設定為 true ,不過當此屬性為 true 的時候,該 WPF 視窗將不能作為 WinForm 控制元件或者 ActiveX 控制元件的宿主了。所以需要慎重考慮。

最後附上全部程式碼以及使用方式,以供查閱!

Generic.xaml 的內容:

< ResourceDictionary xmlns ="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

     xmlns : x ="http://schemas.microsoft.com/winfx/2006/xaml"

     xmlns : sys ="clr-namespace:System;assembly=mscorlib"

     xmlns : l ="clr-namespace:CustomWindowDemo">

 

    < l : BoolToVisibilityConverter x : Key ="BoolToVisibilityConverter"></ l : BoolToVisibilityConverter >

 

    < Style x : Key ="styleWindowButtonMinimize" BasedOn ="{ x : Null }" TargetType ="{ x : Type Button }">

        < Setter Property ="Template">

            < Setter.Value >

                < ControlTemplate TargetType ="{ x : Type Button }">

                    < Grid x : Name ="buttonClose">

                        < Ellipse Stroke ="{ x : Null }" StrokeThickness ="1" x : Name ="btnEllipse" >

                            < Ellipse.Fill >

                                < RadialGradientBrush >

                                    < GradientStop Color ="#BFABA7A4" Offset ="0.777"/>

                                     < GradientStop Color ="#FF897F77" Offset ="1"/>

                                </ RadialGradientBrush >

                            </ Ellipse.Fill >

                        </ Ellipse >

 

                        < Path x : Name ="iconMin" Width ="11.1641" Height ="2.06641" Canvas.Left ="3.97266" Canvas.Top ="8.51962" Stretch ="Fill" Fill ="#FFFFFFFF" Data ="F1 M 5.00659,8.51962C 4.43613,8.51831 3.97266,8.98184 3.97266,9.55347C 3.97266,10.1238 4.435,10.586 5.00659,10.586L 14.1028,10.586C 14.6733,10.586 15.1353,10.1238 15.1367,9.55215C 15.1367,8.98056 14.6733,8.51962 14.1028,8.51962L 5.00659,8.51962 Z "/>

                         < ContentPresenter SnapsToDevicePixels ="{ TemplateBinding SnapsToDevicePixels }" HorizontalAlignment ="{ TemplateBinding HorizontalContentAlignment }" VerticalAlignment ="{ TemplateBinding VerticalContentAlignment }" RecognizesAccessKey ="True"/>

                    </ Grid >

                    < ControlTemplate.Triggers >

                        < Trigger Property ="IsFocused" Value ="True"/>

                        < Trigger Property ="IsDefaulted" Value ="True"/>

                        < Trigger Property ="IsMouseOver" Value ="True">

                            < Setter Property ="Fill" Value ="#FF5D4E3E" TargetName ="btnEllipse"/>

                        </ Trigger >

                        < Trigger Property ="IsPressed" Value ="True"/>

                        < Trigger Property ="IsEnabled" Value ="False"/>

                    </ ControlTemplate.Triggers >

                </ ControlTemplate >

            </ Setter.Value >

        </ Setter >

    </ Style >

 

    < Style x : Key ="styleWindowButtonMaximize" BasedOn ="{ x : Null }" TargetType ="{ x : Type ToggleButton }">

        < Setter Property ="Template">

            < Setter.Value >

                < ControlTemplate TargetType ="{ x : Type ToggleButton }">

                    < Grid >

                        < Ellipse x : Name ="btnEllipse" Stroke ="{ x : Null }" StrokeThickness ="1">

                            < Ellipse.Fill >

                                < RadialGradientBrush >

                                    < GradientStop Color ="#BFABA7A4" Offset ="0.777"/>

                                    < GradientStop Color ="#FF897F77" Offset ="1"/>

                                </ RadialGradientBrush >

                            </ Ellipse.Fill >

                        </ Ellipse >

 

                        < Path x : Name ="iconMax" Width ="12.4011" Height ="9.93359" Stretch ="Fill" Fill ="#FFFFFFFF" Data ="F1 M 390.641,289.034C 389.073,289.034 387.8,290.308 387.8,291.875L 387.8,296.125C 387.8,297.692 389.073,298.967 390.641,298.967L 397.362,298.967C 398.927,298.967 400.201,297.692 400.201,296.125L 400.201,291.875C 400.201,290.308 398.927,289.034 397.362,289.034L 390.641,289.034 Z M 389.399,296.125L 389.399,291.875C 389.399,291.19 389.956,290.634 390.641,290.634L 397.362,290.634C 398.045,290.634 398.602,291.19 398.602,291.875L 398.602,296.125C 398.602,296.81 398.045,297.367 397.362,297.367L 390.641,297.367C 389.956,297.367 389.399,296.81 389.399,296.125 Z "/>

 

                        < Path x : Name ="iconRestore" Visibility ="Collapsed" Width ="11.6719" Height ="9.48242" Stretch ="Fill" Fill ="#FFFFFFFF" Data ="F1 M 411.826,302.421C 411.802,301.775 411.28,301.259 410.629,301.259L 404.483,301.259C 403.836,301.257 403.312,301.775 403.286,302.421L 403.277,302.421C 403.277,302.421 403.277,303.254 403.277,304.177L 407.126,304.177C 407.984,304.177 408.679,304.853 408.722,305.728L 408.722,307.822L 410.629,307.822C 411.294,307.822 411.834,307.283 411.836,306.615C 411.836,306.507 411.836,302.421 411.836,302.421L 411.826,302.421 Z M 407.126,304.956L 400.979,304.956C 400.545,304.955 400.19,305.301 400.164,305.728L 400.164,309.925C 400.164,310.374 400.531,310.741 400.981,310.741L 407.126,310.741C 407.575,310.741 407.942,310.374 407.944,309.923L 407.934,305.742C 407.918,305.301 407.565,304.956 407.126,304.956 Z "/>

 

                        < ContentPresenter SnapsToDevicePixels ="{ TemplateBinding SnapsToDevicePixels }" HorizontalAlignment ="{ TemplateBinding HorizontalContentAlignment }" VerticalAlignment ="{ TemplateBinding VerticalContentAlignment }" RecognizesAccessKey ="True"/>

                    </ Grid >

                    < ControlTemplate.Triggers >

                        < Trigger Property ="IsFocused" Value ="True"/>

                        < Trigger Property ="IsMouseOver" Value ="True">

                            < Setter Property ="Fill" Value ="#FF6E8F9A" TargetName ="btnEllipse"/>

                         </ Trigger >

                        < Trigger Property ="IsPressed" Value ="True"/>

                        < Trigger Property ="IsEnabled" Value ="False"/>

                        < Trigger Property ="IsChecked" Value ="True">

                            < Setter TargetName ="iconMax" Property ="Visibility" Value ="Collapsed" />

                            < Setter TargetName ="iconRestore" Property ="Visibility" Value ="Visible" />

                        </ Trigger >

                    </ ControlTemplate.Triggers >

                </ ControlTemplate >

            </ Setter.Value >

        </ Setter >

    </ Style >

 

    < Style x : Key ="styleMainWindowButtonClose" BasedOn ="{ x : Null }" TargetType ="{ x : Type Button }">

        < Setter Property ="Template">

            < Setter.Value >

                < ControlTemplate TargetType ="{ x : Type Button }">

相關推薦

定義WPF 視窗樣式

原文: 自定義WPF 視窗樣式 自定義 Window 在客戶端程式中,經常需要用到自定義一個 Window ,大部分是為了好看吧。做了很多研究和實踐之後,覺得需要把這個過程寫下來,以供查閱。 WPF 提供的豐富的功能使得自定義

定義WPF關閉視窗事件觸發的函式

背景:例如我在點選視窗關閉按鈕時候要執行的函式有一個,名為Window_Closing那麼我需要在介面控制元件初始化後新增到Closing中public SerialOption() { InitializeComponent();

WPF 定義鍵盤焦點樣式(FocusVisualStyle)

WPF 自帶的鍵盤焦點樣式是與傳統控制元件樣式搭配的,但 WPF 憑著其強大的自定義樣式的能力,做出與傳統控制元件樣式完全不同風格的 UI 簡直易如反掌。這時,其自帶的鍵盤焦點樣式(FocusVisua

CSS3定義滾動條樣式 -webkit-scrollbar

play 偽類 thumb area 沒有 :link 現在 自定義滾動條 box ::-webkit-scrollbar {/*隱藏滾輪*/display: none;} 前言 webkit支持擁有overflow屬性的區域,列表框,下拉菜單,textarea的滾動條自定

CSS3定義滾動條樣式 之 -webkit-scrollbar

selection 單獨 窗口 請求 方塊 利用 源碼 bsp 進行 有沒有覺得瀏覽器自帶的原始滾動條很不美觀,同時也有看到很多網站的自定義滾動條顯得高端,就連chrome32.0開發板都拋棄了原始的滾動條,美觀多了。那webkit瀏覽器是如何自定義滾動條的呢? 前言

css定義滾動條樣式定義文字選擇樣式,設置文字不被選擇

sed 分享 play gpo radi https cal hid 右移 ::-webkit-scrollbar 滾動條整體部分 ::-webkit-scrollbar-thumb 滾動條裏面的小方塊,能向上向下移動(或往左往右移動,取決於是垂直滾動條還是水平滾動條)

Laravel 定義分頁樣式

建立 img each IV com mina nta ner names 操作步驟如下: (1) 對應public/css/paging.css 文件建立分頁樣式. (2) 控制器查出分頁數據使用 paginate函數進行分頁處理.(禁止使用group by處理查詢)

定義滾動條樣式-transition無效

swe 我們 contain not dep bar ray 就是 overflow 問題 需求是自定義滾動條樣式,然後2秒內無操作隱藏滾動條。 2s內隱藏比較麻煩,不能用css實現,只能監聽容器的touch事件,然後給滾動條加個opacity: 0的class。 .cla

定義WPF窗體形狀

adobe hot blog nop 工具 back enc mask translate 介紹 你好WPF愛好者。 隨著WPF等統一API語言的發明,豐富用戶界面變得非常容易。 創建豐富的用戶界面只是一個想法。 您需要擁有的是創造性思維和最新技術融合。 WPF和Expre

cursor url 定義鼠標樣式

body int 方式 光標 png ctrl 格式 code 背景 cursor可以自定義鼠標寫法是cursor:url(“圖片路徑”),default url:需使用的自定義光標的 URL。圖片類型需要是.cur或.ani格式的。 pointer: 默認的鼠標光標樣

Thinkphp5 定義分頁樣式顯示頁碼和數量

原文章地址:http://www.zhaisui.com/article/52.html Thinkphp5 自帶的分頁比較簡單,本文通過修改Bootstrap類自定義顯示分頁的頁碼和數量 一、修改完成後如下圖顯示 二、修改Bootstr

定義input radio樣式

input[type="radio"]+span::before{ content: "\a0";//不換行空格 display: inline-block; verti

CAD編輯器中怎麼定義文字屬性樣式

想問一下大家在編輯圖紙的時候有沒有遇到過這樣的問題,就是在CAD繪圖的時候,要給編輯的圖紙中做一下特別的說明,但是CAD編輯器中原有的文字樣式部署那麼的符合,拿在CAD編輯器中怎麼自定義文字屬性樣式?具體要怎麼來進行操作?下面小編就來教教大傢俱體的操作,有興趣的朋友可以來看看。 第一步:首先,開啟電腦,看一

CAD編輯器中怎麽定義文字屬性樣式

ado 小夥伴 操作 新版本 e30 ces images 新版 fff 想問一下大家在編輯圖紙的時候有沒有遇到過這樣的問題,就是在CAD繪圖的時候,要給編輯的圖紙中做一下特別的說明,但是CAD編輯器中原有的文字樣式部署那麽的符合,拿在CAD編輯器中怎麽自定義文字屬性樣式?

vue定義多選樣式

自定義多選框樣式 平時一直用的框架中的樣式,這次不行了 要自己寫。 做個筆記記錄一下 很久沒寫這中樣式了 設計要求的樣式 其實那個勾並不是checkbox,而是一個i標籤,給他的兩邊設定border

定義placeholder的樣式和顏色

.tes ::-webkit-input-placeholder { color: red; text-indent: .4rem;

微信小程式——定義底部導航樣式切換

1、以下截圖是靜態展示部分 解析: 1、catchtap='goHome' 是點選事件,點選的時候傳遞data-num='1',點選事件方法名都是一樣的,只是傳入的data-num值不同,通過這個不同的值,使用三元運算子來判斷需要顯示的樣式和圖示 2、圖示切換,通過

定義滾動條樣式相容所有瀏覽器

萬惡的瀏覽器相容 看人家chrome多麼友好,幾行css就能自定義樣式,ie和火狐各種不行,如果只要求部分相容的可以直接用css寫 chorme <div class="bar"></

[Swift通天遁地]一、超級工具-(14)使用SweetAlert製作漂亮的定義Alert視窗

本文將演示一款非常強大的警告視窗。 Github地址:【SweetAlert】 下載所需的第三方類庫。在下載的資料夾中,選擇: 【SweetAlert】->【SweetAlert.swift】拖動到專案中 ->在彈出的新增檔案視窗中,保持預設的設定選項->【Finish】 在專案導

CSS定義滑鼠指標樣式

原文連結: http://davidwalsh.name/css-custom-cursorDemo地址: http://davidwalsh.name/demo/css-custom-cursor.php原文日期: 2014-09-16翻譯日期: 2014-09-17翻譯人