WPF 圓型佈局(測量過程)

這個例子來自書上。html

記錄過程。ide

主要是數學上極座標,WPF中的測量過程函數

簡單來講在一個具備固定軸的座標系內,一個由原點射出的向量並與固定軸有必定角度且在向量上肯定長度的這麼個東西。佈局

能夠參考:this

知乎https://www.zhihu.com/question/318613418/answer/640194590spa

B站https://www.bilibili.com/video/BV1Sb411n7FG?t=1773d

極座標與直角座標系轉換。code

極座標中某一點是M,也就是M(ρ,θ)。orm

將M鏈接至原點成爲一個線段L1,將此線段放置直角座標系,其中M點變爲點M1(X,Y)。htm

此時咱們能夠利用三角函數肯定X,Y

X=ρ*cosθ=L1*X[點在X軸的垂線座標]/L1

Y=ρ*sinθ=L1*Y[點在Y軸的垂線座標]/L1

L1也能夠理解爲半徑

那麼直角座標轉換爲極座標則是M(X,Y),一樣咱們需使用圓的標準方程(以前的極座標轉直角中的L1,原本就應該是R【半徑】,不過我不太喜歡這麼快,先用線段,這麼好理解) R2=X2+Y2

另外還有三角函數tan,對邊比鄰邊 ,(座標系內)y/x

ρ=根號下X2+Y2

θ=tan=y/x

 

剩下就是WPF的測量過程

沒什麼好說,第一步是測量,第二步是排列。

第一步主要是Measure方法,可是主要是經過MeasureOverride方法來肯定,這個方法自己是預計UI的大小,Measure是沒有返回值,可是有形參,是這個控件的父控件留給這個控件的可用空間,

若是控件重寫measureoverride方法,這個方法的形參就是Measure的形參,同時也會和Measure造成遞歸佈局更新,

第二步是Arrange,是最終確認UI控件的大小,一般是經過ArrageOvrride方法確認,過程和第一步差很少,只不過形參和返回值不一樣。由於要定位,因此是Rect。

 

對於Measure是父控件給子控件賦值通知子控件你可用大小

MeasureOverride是測量自身大小並返回通知父控件我預計用這麼大(DesiredSize)

對於Arrange是父控件決定子控件的位置和大小

ArrangeOverride是肯定自身大小和位置而後返回最終的大小(finalsize【在這以前會有rendersize】)

具體過程還能夠參考https://www.cnblogs.com/powertoolsteam/archive/2011/01/10/1932036.html

 

差很少就這麼多

class Test : Panel
    {
        public static readonly DependencyProperty RadiusProperty = DependencyProperty.Register("Radius", typeof(double), typeof(Test), new PropertyMetadata(0.0, new PropertyChangedCallback(OnValueChanged)));
        public double Radius
        {
            get => Convert.ToDouble(GetValue(RadiusProperty));
            set => SetValue(RadiusProperty, value);
        }


        private static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            (d as Test).Radius = Convert.ToDouble(e.NewValue);
            (d as Test).InvalidateArrange();
        }
      
        protected override Size MeasureOverride(Size availableSize)
        {
           
            double MaxElementWidth = 0;
            foreach(UIElement item in Children)
            {
//給定子控件的可用空間 item.Measure(availableSize); MaxElementWidth
= Math.Max(item.DesiredSize.Width, MaxElementWidth); } double PanelWidth = 2 * this.Radius+2 * MaxElementWidth; double width = Math.Min(PanelWidth, availableSize.Width); double height = Math.Min(PanelWidth, availableSize.Height); return new Size(width, height); } protected override Size ArrangeOverride(Size finalSize) { double Degree = 0; double DegreeSrep = (double)360 / this.Children.Count; double X = this.DesiredSize.Width / 2; double Y = this.DesiredSize.Height / 2; foreach(UIElement Item in Children) { //角度轉弧度 double angle = Math.PI * Degree / 180.0; //轉換爲直角座標系 r*cos double x = Math.Cos(angle) * this.Radius; //轉換爲直角座標系 r*sin double y = Math.Sin(angle) * this.Radius; RotateTransform rotate = new RotateTransform(); rotate.Angle = Degree; rotate.CenterX = 0; rotate.CenterY = 0; Item.RenderTransform = rotate; //決定子控件的位置和大小 Item.Arrange(new Rect(X + x, Y + y, Item.DesiredSize.Width, this.DesiredSize.Height)); Degree += DegreeSrep; } return finalSize; } }

 

xaml

<Grid>
        <local:Test Radius="50">
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
            <TextBlock Text="abc"/>
        </local:Test>
    </Grid>

 

相關文章
相關標籤/搜索