1. 程式人生 > >WPF入門教程系列六——布局介紹與Canvas(一)

WPF入門教程系列六——布局介紹與Canvas(一)

mouse 建議 geo 自動調整 範圍 添加 ges ans colors

從這篇文章開始是對WPF中的界面如何布局做一個較簡單的介紹,大家都知道:UI是做好一個軟件很重要的因素,如果沒有一個漂亮的UI,功能做的再好也無法吸引很多用戶使用,而且沒有漂亮的界面,那麽普通用戶會感覺這個軟件沒有多少使用價值。

一. 總體介紹

WPF的布局控件都在System.Windows.Controls.Panel這個基類下面,使用 WPF提供的各種控件在WPF應用程序中界面進行布局,同時對各種子控件(如按鈕、文本框,下拉框等)進行排列組合。

技術分享

Pane類的公共屬性太多了。就簡單介紹幾個常見的屬性如下表。

名稱

說明

Cursor

獲取或設置在鼠標指針位於此元素上時顯示的光標。

DataContext

獲取或設置元素參與數據綁定時的數據上下文。

Dispatcher

獲取與此 DispatcherObject 關聯的 Dispatcher。

FontFamily

獲取或設置控件的字體系列。

FontSize

獲取或設置字號。

FontWeight

獲取或設置指定的字體的權重或粗細。

Foreground

獲取或設置描述前景色的畫筆。

HandlesScrolling

獲取一個值控件是否支持滾動。

Height

獲取或設置元素的建議高度。

HorizontalContentAlignment

獲取或設置控件內容的水平對齊。

IsLoaded

獲取一個值,該值指示是否已加載此元素以供呈現。

IsMouseOver

獲取一個值,該值指示鼠標指針是否位於此元素(包括可視樹上的子元素)上。這是一個依賴項屬性。

IsTabStop

獲取或設置一個值控制是否在選項卡上導航包含。

IsVisible

獲取一個值,該值指示此元素在用戶界面 (UI) 中是否可見。這是一個依賴項屬性。

LayoutTransform

獲取或設置在執行布局時應該應用於此元素的圖形轉換方式。

Margin

獲取或設置元素的外邊距。

Name

獲取或設置元素的標識名稱。 該名稱提供一個引用,以便當 XAML 處理器在處理過程中構造標記元素之後,代碼隱藏(如事件處理程序代碼)可以對該元素進行引用。

Opacity

獲取或設置當 UIElement 在用戶界面 (UI) 中呈現時為其整體應用的不透明度因子。這是一個依賴項屬性。

Padding

獲取或設置控件中的空白。

RenderTransform

獲取或設置影響此元素的呈現位置的轉換信息。這是一個依賴項屬性。

TabIndex

獲取或設置使用 tab 鍵時,確定順序接收焦點的元素的值,當用戶將控件定位。

Tag

獲取或設置任意對象值,該值可用於存儲關於此元素的自定義信息。

ToolTip

獲取或設置在用戶界面 (UI) 中為此元素顯示的工具提示對象。

TouchesCaptured

獲取在此元素上捕獲的所有觸摸設備。

TouchesCapturedWithin

獲取在此元素或其可視化樹中的任何子元素上捕獲的所有觸摸設備。

VerticalContentAlignment

獲取或設置控件內容的垂直對齊方式。

Visibility

獲取或設置此元素的用戶界面 (UI) 可見性。這是一個依賴項屬性。

VisualOpacityMask

獲取或設置 Brush 值,該值表示 Visual 的不透明蒙板。

Width

獲取或設置元素的寬度。

一個Panel 的呈現就是測量和排列子控件,然後在屏幕上繪制它們。所以在布局的過程中會經過一系列的計算,那麽子控件越多,執行的計算次數就越多,則性能就會變差。如果不需要進行復雜的布局,則盡量少用復雜布局控件(如 Grid和自定義復雜的Panel);如果能簡單布局實現就盡量使用構造相對簡單的布局(如 Canvas、UniformGrid等),這種布局可帶來更好的性能。 如果有可能,我們應盡量避免調用 UpdateLayout方法。
每當Panel內的子控件改變其位置時,布局系統就可能觸發一個新的處理過程。對此,了解哪些事件會調用布局系統就很重要,因為不必要的調用可能導致應用程序性能變差。
換句話說,布局是一個遞歸系統,實現在屏幕上對控件進行大小調整、定位和繪制,然後進行呈現。具體如下圖,要實現控件0的布局,那麽先要實現0的子控件 01,02...的布局,要實現01的布局,那麽得實現01的子控件001,002...的布局,如此循環直到子控件的布局完成後,再完成父控件的布局, 最後遞歸回去直到遞歸結束,這樣整個布局過程就完成了.

技術分享

布局系統為Panel中的每個子控件完成兩個處理過程:測量處理過程(Measure)和排列處理過程(Arrange)。每個子 Panel 均提供自己的 MeasureOverride 和 ArrangeOverride 方法,以實現自己特定的布局行為。

二. Canvas

Canvas是最基本的面板,只是一個存儲控件的容器,它不會自動調整內部元素的排列及大小,它僅支持用顯式坐標定位控件,它也允許指定相對任何角的坐標,而不僅僅是左上角。可以使用Left、Top、Right、 Bottom附加屬性在Canvas中定位控件。通過設置Left和Right屬性的值表示元素最靠近的那條邊,應該與Canvas左邊緣或右邊緣保持一個固定的距離,設置Top和Bottom的值也是類似的意思。實質上,你在選擇每個控件停靠的角時,附加屬性的值是作為外邊距使用的。如果一個控件沒有使 用任何附加屬性,它會被放在Canvas的左上方(等同於設置Left和Top為0)。

Canvas的主要用途是用來畫圖。Canvas默認不會自動裁減超過自身範圍的內容,即溢出的內容會顯示在Canvas外面,這是因為默認 ClipToBounds=”False”;我們可以通過設置ClipToBounds=”True”來裁剪多出的內容。

接下來我們來看兩個實例,第一個實例使用XAML代碼實現:

技術分享
<Window x:Class="WpfApp1.WindowCanvas"

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

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

        Title="WindowCanvas" Height="400" Width="500">

    <Grid>

        <Canvas Margin="0,0,0,0" Background="White">

            <Rectangle Fill="Blue" 

                Stroke="Azure" 

                Width="250" 

                Height="200" 

                Canvas.Left="210" Canvas.Top="101"/>

            <Ellipse Fill="Red" 

                Stroke="Green" 

                Width="250" Height="100" 

                Panel.ZIndex="1" 

                Canvas.Left="65" Canvas.Top="45"/>

        </Canvas>

        <Canvas>

            <Button Name="btnByCode" Click="btnByCode_Click">後臺代碼實現</Button>

        </Canvas>

    </Grid>

</Window>

 
技術分享

實例後的效果如下圖。

技術分享

第二個實例,我們使用後臺代碼來實現。我使用C#來實現

技術分享
using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Shapes;

 

namespace WpfApp1

{

    /// <summary>

    /// WindowCanvas.xaml 的交互邏輯

    /// </summary>

    public partial class WindowCanvas : Window

    {

        public WindowCanvas()

        {

            InitializeComponent();

            

        }

 

        public void DisplayCanvas()

        {

            Canvas canv = new Canvas();

            //把canv添加為窗體的子控件

            this.Content = canv;

            canv.Margin = new Thickness(0, 0, 0, 0);

            canv.Background = new SolidColorBrush(Colors.White);

 

            //Rectangle

            Rectangle r = new Rectangle();

            r.Fill = new SolidColorBrush(Colors.Red);

            r.Stroke = new SolidColorBrush(Colors.Red);

            r.Width = 200;

            r.Height = 140;

            r.SetValue(Canvas.LeftProperty, (double)200);

            r.SetValue(Canvas.TopProperty, (double)120);

            canv.Children.Add(r);

            //Ellipse

            Ellipse el = new Ellipse();

            el.Fill = new SolidColorBrush(Colors.Blue);

            el.Stroke = new SolidColorBrush(Colors.Blue);

            el.Width = 240;

            el.Height = 80;

            el.SetValue(Canvas.ZIndexProperty, 1);

            el.SetValue(Canvas.LeftProperty, (double)100);

            el.SetValue(Canvas.TopProperty, (double)80);

            canv.Children.Add(el);

 

        }

 

        private void btnByCode_Click(object sender, RoutedEventArgs e)

        {

            DisplayCanvas();

        }

    }

}

 
技術分享

實現後的效果如下圖。

技術分享

最後 要說明一點Canvas內的子控件不能使用兩個以上的Canvas附加屬性,如果同時設置Canvas.Left和Canvas.Right屬性,那麽後者將會被忽略。

WPF入門教程系列六——布局介紹與Canvas(一)