網(wǎng)站首頁 編程語言 正文
作為一個(gè)WPF控件開發(fā)者,我在工作中經(jīng)常遇到如本文標(biāo)題所示的問題。其實(shí),這個(gè)問題并不是很難,只是在操作上有些繁瑣。本文將嘗試對這個(gè)問題進(jìn)行解答,并且對相關(guān)的一些技術(shù)細(xì)節(jié)加以探討。
先從我遇到的一個(gè)典型的問題開始吧:寫一個(gè)MyElement類,要求如下:
- 從FrameworkElement繼承
- 增加一個(gè)Button到它的VisualTree上
在Visual上有一個(gè)AddVisualChild方法,相信很多剛接觸這個(gè)方法的同學(xué)們(好吧,至少我是這樣)都會“顧名思義”地認(rèn)為這個(gè)方法就可以解決本文的問題。再加上MSDN上也給出了一個(gè)例子來“火上澆油”一把。于是,一陣竊喜之后,我興奮地敲出了以下代碼:
class MyElement : FrameworkElement
{
private Button _button = new Button() { Content = "I'm a Button!"};
public MyElement()
{
this.AssembleVisualChildren();
}
private void AssembleVisualChildren()
{
this.AddVisualChild(this._button);
}
protected override int VisualChildrenCount
{
get
{
return 1;
}
}
protected override Visual GetVisualChild(int index)
{
return this._button ;
}
}
然后將這個(gè)MyElement加入測試窗口,代碼如下:
<Window
x:Class="AddVisualChildTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:loc="clr-namespace:AddVisualChildTest"
WindowStartupLocation="CenterScreen"
Title="Window1" Height="300" Width="300">
<Grid>
<loc:MyElement Margin="10"/>
</Grid>
</Window>
運(yùn)行后的結(jié)果如下:
空空如也!嗯,被忽悠了。一陣失落、打擊之后,我的好奇心被激發(fā)了:這是為什么呢?于是我狂找資料,終于被我發(fā)現(xiàn)了:
實(shí)際上,在上面這個(gè)例子中,AddVisualChild這個(gè)方法只是在MyElement和Button之間建立起了一種VisualTree上的父子關(guān)系,但是并沒有將Button掛接到MyElement的VisualTree上,所以最終我們沒有在屏幕上看到這個(gè)Button。
為了將Button真正掛接到MyElement的VisualTree上,還需要額外做一件事情:在VisualTree上為這個(gè)Button分配空間并且指定位置,這個(gè)過程叫做Layout。此過程分兩個(gè)部分:一個(gè)是Measure,另一個(gè)是Arrange。這兩個(gè)過程在FrameworkElement上對應(yīng)著兩個(gè)方法:MeasureOverride和ArrangeOverride方法。具體做法如下:
protected override Size MeasureOverride(Size availableSize)
{
if (this.VisualChildrenCount > 0)
{
UIElement child = this.GetVisualChild(0) as UIElement;
Debug.Assert(child != null); // !Assert
child.Measure(availableSize);
return child.DesiredSize;
}
return availableSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
Rect arrangeRect = new Rect()
{
Width = finalSize.Width,
Height = finalSize.Height
};
if (this.VisualChildrenCount > 0)
{
UIElement child = this.GetVisualChild(0) as UIElement;
Debug.Assert(child != null); // !Assert
child.Arrange(arrangeRect);
}
return finalSize;
}
再次運(yùn)行程序:
目標(biāo)實(shí)現(xiàn)。
由此,我們可以總結(jié)出這個(gè)問題的解決方案如下:
在MyElement的構(gòu)造器中調(diào)用AddVisualChild方法;
重寫VisualChildCount屬性;
重寫GetVisualChild方法;
重寫MeasureOverride方法;
重寫ArrangeOverride方法;?
另外,WPF在此問題的解決上也為開發(fā)者提供了一些必要的幫助。就我所知的,有如下幾個(gè)內(nèi)容:
1、Panel
還是本文開始提到的問題,只不過要將其中的FrameworkElement換為Panel。除了上面所提到的方法,Panel為我們提供了更加方便的實(shí)現(xiàn)方式。代碼如下:
class MyElement : Panel
{
private Button _button = new Button() { Content = "I'm a Button!" };
public MyElement()
{
this.Children.Add(_button);
}
protected override Size MeasureOverride(Size availableSize)
{
if (this.VisualChildrenCount > 0)
{
UIElement child = this.GetVisualChild(0) as UIElement;
Debug.Assert(child != null); // !Assert
child.Measure(availableSize);
return child.DesiredSize;
}
return availableSize;
}
protected override Size ArrangeOverride(Size finalSize)
{
Rect arrangeRect = new Rect()
{
Width = finalSize.Width,
Height = finalSize.Height
};
if (this.VisualChildrenCount > 0)
{
UIElement child = this.GetVisualChild(0) as UIElement;
Debug.Assert(child != null); // !Assert
child.Arrange(arrangeRect);
}
return finalSize;
}
}
之所以能這樣做的原因是Panel已經(jīng)替我們將如下幾個(gè)工作封裝在了UIElementCollection(Panel的Children屬性)中:
AddVisualChild
VisualChildCount
GetVisualChild
2、VisualCollection
另外,在這個(gè)過程中,我們還可以使用一個(gè)叫做VisualCollection的類來作為所有 Visual Child的容器。這個(gè)容器構(gòu)造的時(shí)候需要一個(gè)Visual類型的Parent,然后在添加、刪除Visual Child的時(shí)候,它的相應(yīng)方法(Add,Remove)就會幫助我們自動(dòng)調(diào)用Parent的AddVisualChild和RemoveVisualChild方法。如此一來,我們的工作量又減少了。
原文鏈接:https://www.cnblogs.com/AaronLu/archive/2009/11/09/1599348.html
相關(guān)推薦
- 2023-11-26 解決:element ui表格表頭自定義輸入框單元格el-input不能輸入問題
- 2023-01-30 delphi?判斷字符串是否為純字母組合的函數(shù)_Delphi
- 2022-05-26 C++的深淺拷貝和寫時(shí)拷貝你了解嗎_C 語言
- 2022-05-22 使用VirtualBox和Vagrant搭建Linux環(huán)境的方法步驟_VirtualBox
- 2022-04-15 利用Python實(shí)現(xiàn)數(shù)值積分的方法_python
- 2022-02-22 Android對話框AlertDialog詳解_Android
- 2023-02-15 刪除docker中沒有被使用的數(shù)據(jù)卷volume_docker
- 2022-07-17 C++深入講解namespace與string關(guān)鍵字的使用_C 語言
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支