当前位置:首 页 > 攻城湿 >Silverlight > 查看文章

Geometry was one of the coolest topics in school for me. Probably because it uses a lot of figures to convey the concepts. Here I am trying to explain how we can leverage the Layout system in WPF and Silver light by taking an example of creating a Radial Panel. A RadialPanel lays out its children in a circular fasion. So before going in to the technical details, let us see how this problem get solved algorithmically.If you are asked to arrange a bunch of items in a circular path, what all things would you consider?.
1) How much space do I have? – Say X * Y rectangular area is the available size.
2) I will draw an approximate Circle (Or ellipse) inside the X*Y space. Assuming that the Radii are ‘Rx and Ry’
3) How many items are there to arrange? Say N – number
4) I know that 360 degrees are the total angular space for a circle. So angular distance between each item will be 360/N degrees.
6) I can calculate the coordinate point to which an item should be placed. That is by doing the following simple trigonometry operation. The coordinate point will be at Rx * Cos (Angle), Ry*Sin (Angle).
The math can be visualized from the figure bellow.

math_Radial

It is so interesting that WPF has kept the custom panel implementation in such a way that we can easily code the above steps directly in to code. First of all you have to create a class derived from the System.Controls.Panel. The two methods we need to override are

protected override Size MeasureOverride(Size availableSize) – In this pass you can do the following.

Iterate the collection of children that are part of layout, call Measure() on each child element.

Compute the net desired size of the parent based upon the measurement of the child elements.

protected override Size ArrangeOverride(Size finalSize) –

Iterate the collection of children that are part of layout, call Arrange() function on each child element.

Compute the net final size of the panel based upon the arrangement of the child elements.

Here is the implementation of the RadialPanel. Hope the comments in between explains the relvance of each step.

public class RadialPanel : Panel

    {

        // Measure each children and give as much room as they want 

 

        protected override Size MeasureOverride(Size availableSize)

        {

            foreach (UIElement elem in Children)

            {

                //Give Infinite size as the avaiable size for all the children

                elem.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

            }

            return base.MeasureOverride(availableSize);

        }

 

        //Arrange all children based on the geometric equations for the circle.

        protected override Size ArrangeOverride(Size finalSize)

        {

            if (Children.Count == 0)

                return finalSize;

 

            double _angle = 0;

 

            //Degrees converted to Radian by multiplying with PI/180

            double _incrementalAngularSpace = (360.0 / Children.Count) * (Math.PI / 180);

 

            //An approximate radii based on the avialable size , obviusly a better approach is needed here.

            double radiusX = finalSize.Width / 2.4;

            double radiusY = finalSize.Height / 2.4;

 

            foreach (UIElement elem in Children)

            {

                //Calculate the point on the circle for the element

 

                Point childPoint = new Point(Math.Cos(_angle) * radiusX, -Math.Sin(_angle) * radiusY);

                //Offsetting the point to the Avalable rectangular area which is FinalSize.

                Point actualChildPoint = new Point(finalSize.Width / 2 + childPoint.X - elem.DesiredSize.Width / 2,finalSize.Height / 2 + childPoint.Y - elem.DesiredSize.Height / 2);

 

                //Call Arrange method on the child element by giving the calculated point as the placementPoint.

                elem.Arrange(new Rect(actualChildPoint.X, actualChildPoint.Y, elem.DesiredSize.Width, elem.DesiredSize.Height));

 

                //Calculate the new _angle for the next element

                _angle += _incrementalAngularSpace;

 

            }

 

            return finalSize;

        }

    }

And finally the XAML file and its preview has shown bellow from VS2008 , And you can use the same Panel class in a SilverLight2.0 project with the same XAML usage .

VSTS_RadialPanel

The following screen shows all the System.Media.Colors in an ItemsControl which intern has RadialPanel as its ItemsPanel.

Colors_radial

The XAML for this is pasted bellow.

<window x:Class="WPFSample.Window1"

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

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

    xmlns:local="clr-namespace:WPFSample" 

    Title="Window1" >

    </window><window .Resources>        

        <itemspaneltemplate x:Key="radialTemplate">

            <local:radialpanel></local:radialpanel>

        </itemspaneltemplate>        

        <datatemplate x:Key="enumTemplate">

                <rectangle Width="20" Height="20" Fill="{Binding Name}" ToolTip="{Binding Name}" Stroke="#FF000000"></rectangle>

        </datatemplate>

    </window>

 

    <itemscontrol Name="itemsControl" ItemTemplate="{DynamicResource enumTemplate}" ItemsPanel="{DynamicResource radialTemplate}"></itemscontrol>

 


You will also need this in the code behind to set the ItemsSource property of the ItemsControl.

itemsControl.ItemsSource =  typeof(Colors).GetProperties();

For more details about the WPF Panel concept, I recommend you to read Dr.WPF’s ItemsControl: ‘P’ is for Panel

[原文:http://jobijoy.blogspot.jp/2008/04/simple-radial-panel-for-wpf-and.html]

这家伙很懒,什么都没写!

—— zhaorong

zhaorong
你可能也喜欢Related Posts
众说纷纭Comments
大眼 可爱 大笑 坏笑 害羞 发怒 折磨 快哭了 大哭 白眼 晕 流汗 困 腼腆 惊讶 憨笑 色 得意 骷髅 囧 睡觉 眨眼 亲亲 疑问 闭嘴 难过 淡定 抗议 鄙视 猪头
小提示:直接粘贴图片到输入框试试
努力发送中...
  • 评论最多
  • 最新评论
  • 随机文章
footer logo
未经许可请勿自行使用、转载、修改、复制、发行、出售、发表或以其它方式利用本网站之内容
Copyright © zhaorong All Rights Reserved. 滇ICP备15006105号-1