程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WPF自定義控件 - 布局

WPF自定義控件 - 布局

編輯:關於.NET

一.ScrollViewer

在WPF自定義控件 —— 自繪篇我們做了 一個可拖動的矩形,但你是否發現當矩形拖出背景後就不見了,一般來說對於不 可見區域需要有ScrollBar來呈現,如圖:

對於這一應用在WPF中最常用的應該在控件外面包個ScrollViewer,那 麼如何使得我們的控件支持ScrollViewer呢?

首先我們來了解一下 ScrollViewer基本原理

通過上圖我們可以看到ScrollViewer是以Grid為容器組成的控件,其 中主要包括ScrollContentPresenter,和兩個ScrollBar,其中ScrollBar就是我 們第一張圖中看到那兩條,它也是一個由多個控件組成的復合控件,在這裡先略 過ScrollBar;來看紅色邊框內的ScrollContentPresenter,可以看到我們的控 件CustomerRender在ScrollContentPresenter內,那麼我們控件呈現的位置必定 是由它來控制的。

這個神秘的ScrollContentPresenter到底做了什麼能 讓我們看到一部分內容呢?看下這張圖就清楚了

我們可以知道ScrollContentPresenter實際對我們玩了一個遮罩效果 ,把我們的控件當作一個背景圖,用ScrollBar來移動背景位置,在 ScrollViewer外的控件可視部分統統被裁減掉了。只要繼承UIElement的控件就 可以重載GetLayoutClip方法來剪切區域。

protected override  Geometry GetLayoutClip(Size layoutSlotSize)
{
  return  new RectangleGeometry(new Rect(base.RenderSize));
}

二.ArrangeOverride

ScrollContentPresenter又是如何 控制子元素的坐標呢?重載ArrangeOverride函數便可,具體看代碼注釋

protected override Size ArrangeOverride(Size  arrangeBounds)
{
  //得到集合中的第一個元素
   UIElement visualChild = this.GetVisualChild(0) as UIElement;
  //把子元素的左上角坐標定義到容器之外 
  Point point =  new Point(-40, -50);

  if (visualChild != null)
  {
    Rect finalRect = new Rect(point,  visualChild.DesiredSize);

    //設置元素坐標和大小
    visualChild.Arrange(finalRect);
  }

   return arrangeBounds;
}

這段代碼中參數arrangeBounds 是父容器傳進的值,一般表示你可以有多大的利用空間,這個函數的返回值一般 指的是你控件RenderSize的大小.

RenderSize有什麼用?(歡迎大家補 充)

在onRender裡可以用,比如畫背景。

在MeasureOverride函數 中當參數值為無限大時用來得知可用空間的大小。

三.MeasureOverride

visualChild.DesiredSize的值實際就是我們常用的 ActualHeight和ActualWidth的源頭,也就是控件的實際大小,我們可以重載 MeasureOverride產生。下面是我們的自定義控件用的。

protected override Size MeasureOverride(Size  constraint)
{
  Size size = new Size
    (
    //判斷形參constraint中傳的值大,還是我們的Rectangle的值大, 以最大的那個作為控件的長寬
    Math.Max(double.IsInfinity (constraint.Width) ? this.RenderSize.Width : constraint.Width,  _preivewRectangle.Right),
    Math.Max(double.IsInfinity (constraint.Height) ? this.RenderSize.Height : constraint.Height,  _preivewRectangle.Bottom));
  return size;
}

要說明下的是外容器的大小並不會觸發MeasureOverride(如把窗 體拖大),只會觸發ArrangeOverride,如果你要重新為DesiredSize賦值並通知父 容器請使用Measure函數,它會調用父控件的OnChildDesiredSizeChanged方法來 通知,同理父控件要監聽子控件的大小變化只要重載該方法即可,這個方法可以 一直沿著可視樹向上引發InvalidateMeasure函數,InvalidateMeasure通過 DispatcherPriority為Render來異步調用Measure。

ArrangeOverride中 盡量不要調用本身的Measure,Measure函數會再次調用InvalidateArrange方法 從而引起循環。控件容器放生變化時可以重載OnRenderSizeChanged實現。

Measure和Arrange的具體關系如下圖:

四.補充

如果想要自定義的ScrollBar你可以能要根絕ScrollBar的值 實時進行重繪圖,這個好處是數據量大,你只需呈現當前畫面中的圖形,缺點是 動一動就要重繪。通過例如ScrollViewer裁減的方式,遮罩得時候不會重繪,不 過剛開始呈現的時候數據量大會慢。

另外在復合控件中配合Transform中 的各種類來進行布局,使用CompositionTarget和動畫類可以產生很多效果。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved