欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

WPF實現(xiàn)自定義Panel面板的示例詳解

 更新時間:2023年09月05日 09:29:40   作者:卓爾不設(shè)凡  
WPF中的Panel(面板),是繼承自FrameworkElement的抽象類,表示一個可以用來排列子元素的面板,本文主要來和大家聊聊WPF如何實現(xiàn)自定義Panel,感興趣的可以了解下

WPF中的Panel(面板),是繼承自FrameworkElement的抽象類,表示一個可以用來排列子元素的面板。

在WPF中,一種預(yù)設(shè)了幾種常用的面板,如Grid、StackPanel、WrapPanel等。他們都是繼承自Panel類,并擁有自己的排列子元素的邏輯。

因此,想要自定義一個Panel,核心的問題就是如何排列子元素。

例如,我們做一個軸排列的元素,即元素沿著X、Y軸排列。我們定義,以面板寬度(Width)或者高度(Height)的中點,為坐標(biāo)原點,水平向右為X軸,垂直向下位Y軸。如下圖所示

先上源代碼:

后代代碼:

public class AxisPanel:Panel
    {
       internal static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
           "Oritentation",typeof(Orientation),typeof(AxisPanel),new FrameworkPropertyMetadata(Orientation.Horizontal,FrameworkPropertyMetadataOptions.AffectsArrange));
        /// <summary>
        /// 指示子元素的布局方向
        /// </summary>
        public Orientation Orientation
        {
            get => (Orientation)GetValue(OrientationProperty);
            set => SetValue(OrientationProperty, value);
        }
        /// <summary>
        /// 測量子元素,以確定自己的DesiredSize。
        /// 此方法由父級元素自動調(diào)用
        /// </summary>
        /// <param name="availableSize">父級元素提供給該面板的可用空間尺寸</param>
        /// <returns>此面板對象需要的尺寸(DesiredSize)</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            double width = 0, height = 0;
            switch(Orientation)
            {
                case Orientation.Horizontal:
                    // 水平布局
                    foreach(UIElement child in Children)
                    {
                        child.Measure(availableSize);
                        width += child.DesiredSize.Width;           // 計算面板需要的寬度;
                        if(child.DesiredSize.Height > height)       // 計算面板需要的高度:為所有元素中最大的高度
                        {
                            height = child.DesiredSize.Height;
                        }
                    }
                    break;
                case Orientation.Vertical:
                    // 垂直布局
                    foreach(UIElement child in Children)
                    {
                        child.Measure(availableSize);
                        height += child.DesiredSize.Height;     // 計算面板需要的高度
                        if(child.DesiredSize.Width > width)
                        {
                            width = child.DesiredSize.Width;    // 計算面板需要寬度:為所有元素中最大的寬度
                        }
                    }
                    break;
            }
            return new Size(width, height);
        }
        /// <summary>
        /// 排列子元素
        /// 此方法由父級元素自動調(diào)用
        /// </summary>
        /// <param name="finalSize">父級元素提供給該面板用于布局的最終尺寸。</param>
        /// <returns></returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            double totalWidth = 0, totalHeight = 0;                                         // 面板的總寬度、高度
            switch(Orientation)
            {
                case Orientation.Horizontal:                                                // 水平排列:需要計算子元素左上角的坐標(biāo)點,已經(jīng)用于排列子元素的區(qū)域大小
                    double x1, y1;                                                      // 子元素左上角點的坐標(biāo)
                    for (int i=0;i<Children.Count;i++)
                    {
                        x1 = totalWidth;                                                    // 子元素的x坐標(biāo),應(yīng)該為總寬度的值
                        y1 = (finalSize.Height - Children[i].DesiredSize.Height) / 2;       // 子元素的y坐標(biāo),始終保存在軸上
                        totalWidth += Children[i].DesiredSize.Width;                        // 總寬度增加
                        Rect rect = new(x1, y1, Children[i].DesiredSize.Width, Children[i].DesiredSize.Height);       // 放置子元素的矩形區(qū)域
                        Children[i].Arrange(rect);                                          // 放置子元素
                    }
                    break;
                case Orientation.Vertical:
                    double x2, y2=0;
                    for (int i = 0; i < Children.Count;i++)
                    {
                        x2 = (finalSize.Width - Children[i].DesiredSize.Width) / 2;
                        y2 = totalHeight;
                        totalHeight += Children[i].DesiredSize.Height;                      // 所有子元素的總高度
                        Rect rect2 = new(x2, y2, Children[i].DesiredSize.Width, Children[i].DesiredSize.Height);
                        Children[i].Arrange(rect2);
                    }
                    break;
            }
            return finalSize;
        }
    }

前端代碼:

 <rayPanel:AxisPanel Orientation="Horizontal">
         <Button Content="Button1" Width="100" Height="40"/>
         <Button Content="Button2" Width="100" Height="40" Canvas.Left="100"/>
         <Button Content="Button3" Width="100" Height="40" Canvas.Left="200"/>
         <TextBlock Text="你在么?"/>
     </rayPanel:AxisPanel>

顯示效果如下:

當(dāng)Orientation = “Horizontal”

當(dāng)Orientation="Vertical"

名詞簡寫:

元素:表示一個繼承自UIElement類的實例。

Frame元素:表示一個繼承自FrameworkElement類的實例。

因為FrameworkElement是繼承自UIElement的,因此在很多時候,一個FrameworkElement也可以被稱為元素。只有在涉及到FrameworkElement類自己的屬性、方法時,會被稱為Frame元素。

WPF的布局,分為兩個步驟:

1. 測量:確定子元素需要的尺寸(DesiredSize)。

2. 排列:確定子元素的位置,大小。

1. 測量:

在UIElement中,定義了兩個方法:Measure() 和 MeasureCore()。在FrameworkElement中還定義了MeasureOverride()方法。他們的工作方式是:

1). 父級元素調(diào)用子元素實例的Measure(),此時Measure()方法會做一堆的邏輯檢查,然后調(diào)用其MeasureCore()方法。在MeasureCore()方法中,真正的去計算元素的期望尺寸(DesiredSize)。在UIElement類中,MeasureCore()返回的尺寸永遠(yuǎn)是(0,0)(請看微軟的源代碼:UIElement.MeasureCore())。這意味著如果子元素是一個UIElement的實例,則其期望尺寸永遠(yuǎn)會是(0,0)。

2).FrameworkElement繼承了UIElement,重寫并密封了MeasureCore()方法。因此,當(dāng)調(diào)用子元素的Measure()方法時,子元素的Measure()方法實際上會調(diào)用重寫后的MeasureCore()方法,以計算Frame元素的期望尺寸。

3).在FrameworkElement重寫的MeasureCore()方法中,實際上又會調(diào)用MeasureOverride()方法。MeasureOverride()方法是一個虛方法,可供用戶重寫,以實現(xiàn)用戶自己的測量邏輯,同時還能保證相關(guān)的檢查不被遺漏。

2. 排列:

排列的工作方式,與“測量”是一樣的。不再贅述。

由此可知,要實現(xiàn)自己的布局,就有三個選擇:

1)繼承自UIElement,并重寫MeasureCore()和ArrangeCore()方法(并添加需要的屬性等)。此路徑難度很大。

2)繼承自FrameworkElement,并重寫MeasureOverride()和ArrangeOverride()方法(并添加需要的屬性等)。此路徑難度不小。

3)繼承自Panel,并重寫MeasureOverride()和ArrageOverride()方法(并添加需要的屬性等)。此路徑難度最小。因為Panel類已經(jīng)定義了很多相關(guān)的屬性、方法可共用戶使用。

參數(shù)的意義

在MeasureOverride()和ArrageOverride()方法中,兩個參數(shù)及返回值的意義是不同的:

MeasureOverride():該方法的參數(shù)availableSize,表示父元素,可以用來布局該元素的可用空間。此參數(shù)由WPF布局系統(tǒng)確定;返回值為該元素期望的尺寸(DesiredSize)。自定義面板中,如果用戶不重寫該方法(實現(xiàn)自己的測量方式),則會返回一個(0,0)的期望尺寸。

ArrangeOverride():該方法的參數(shù)finalSize,表示父元素,最終分配給該元素,用于排列子元素的尺寸。當(dāng)WPF的布局系統(tǒng)測量完各控件的尺寸后,開始依次排列子元素。當(dāng)排列到本元素時,剩余的空間可能與MeasureOverride()方法中的availableSize不同。因此此時傳遞進(jìn)來的,是可以用于排列子元素的最終的空間大小。在ArrangeOverride()方法中的,可以按照自己的邏輯去排列子元素。并最終返回一個尺寸值(Size類型),告訴WPF的布局系統(tǒng),該元素最終使用了多少空間。

以上就是WPF實現(xiàn)自定義Panel面板的示例詳解的詳細(xì)內(nèi)容,更多關(guān)于WPF自定義面板的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Unity3D Shader實現(xiàn)動態(tài)星空

    Unity3D Shader實現(xiàn)動態(tài)星空

    這篇文章主要為大家詳細(xì)介紹了Unity3D Shader實現(xiàn)動態(tài)星空,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-04-04
  • WCF實現(xiàn)進(jìn)程間管道通信Demo分享

    WCF實現(xiàn)進(jìn)程間管道通信Demo分享

    下面小編就為大家分享一篇WCF實現(xiàn)進(jìn)程間管道通信Demo,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • C#連接MySQL的兩個簡單代碼示例

    C#連接MySQL的兩個簡單代碼示例

    這篇文章主要介紹了C#連接MySQL的簡單代碼示例,需要的朋友可以參考下
    2017-06-06
  • DataGridView凍結(jié)列或行、列順序調(diào)整、操作行頭列頭標(biāo)題的方法

    DataGridView凍結(jié)列或行、列順序調(diào)整、操作行頭列頭標(biāo)題的方法

    這篇文章介紹了DataGridView凍結(jié)列或行、列順序調(diào)整、操作行頭列頭標(biāo)題的方法,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-02-02
  • C# 編譯生成dll文件供程序調(diào)用的兩種方法

    C# 編譯生成dll文件供程序調(diào)用的兩種方法

    這篇文章主要介紹了C# 編譯生成dll文件供程序調(diào)用的兩種方法,需要的朋友可以參考下
    2018-03-03
  • C#實現(xiàn)計算器功能(winform版)

    C#實現(xiàn)計算器功能(winform版)

    這篇文章主要為大家詳細(xì)介紹了C#實現(xiàn)winform版的計算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • C#復(fù)雜XML反序列化為實體對象兩種方式小結(jié)

    C#復(fù)雜XML反序列化為實體對象兩種方式小結(jié)

    本文主要介紹了C#復(fù)雜XML反序列化為實體對象兩種方式,主要介紹如何把通過接口獲取到的Xml數(shù)據(jù)轉(zhuǎn)換成(反序列化)我們想要的實體對象,感興趣的可以一起來了解一下
    2022-04-04
  • C#簡單實現(xiàn)子窗體向父窗體傳值的方法

    C#簡單實現(xiàn)子窗體向父窗體傳值的方法

    這篇文章主要介紹了C#簡單實現(xiàn)子窗體向父窗體傳值的方法,以實例形式較為詳細(xì)的分析了C#窗體間傳值的實現(xiàn)技巧,具有一定參考借鑒價值,需要的朋友可以參考下
    2015-09-09
  • c# 配置文件App.config操作類庫的方法

    c# 配置文件App.config操作類庫的方法

    下面小編就為大家?guī)硪黄猚# 配置文件App.config操作類庫的方法。小編覺的挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-12-12
  • 基于C#實現(xiàn)高效示波器功能

    基于C#實現(xiàn)高效示波器功能

    這篇文章介紹了用?C#實現(xiàn)示波器功能的方法,包括使用?WinForm?及多種曲線控件,闡述了原理和思路,如定義緩存數(shù)據(jù)的隊列、轉(zhuǎn)化數(shù)組刷新顯示等,還提到注意事項及擴(kuò)展特性,最后呼吁點贊支持和交流,需要的朋友可以參考下
    2024-12-12

最新評論