微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Silverlight中定义布局面板

这是我阅读《Silverlight5 in Action》中一部分的笔记整理,原著中的代码有部分错误,而且注释不多,其中有些细节部分我也没搞太清楚。先做个笔记留作以后查看。

这里的实例是构建一个轨道布局的Panel,就是Panel中的所有控件是分布在一个圆形轨道上的。最终效果如下:

构建自定义布局,肯定需要先理解布局系统的工作原理,然后才能去构建。布局面板需要经过两个阶段才能完成布局,分别是测量阶段和排列阶段。布局面板的基类Panel提供了MeasureOverride和ArrangeOverride两个方法,供子类继承实现特定的布局行为。
在测量布局阶段,会对面板中Children集合InternalChildren的每个子元素(child)进行计算,测量大小。此过程是通过调用child的Measure方法来完成。
在排列布局阶段,同样会对面板中Children集合InteralChildren的每个元素调用Arrange放来完成。

首先定义自己的布局类:

在布局类中首先是定义属性包括依赖属性和附加属性定义的方法。然后是重写MeasureOverride和ArrangeOverride方法

namespace ControlsLib
{
    public class OrbitPanel : Panel
    {
        /// <summary>
        /// 这是一个依赖属性,表示的是OribtPanel中轨道(Orbit)的个数
        /// </summary>
        /// <value>
        /// The number of orbits.
        /// </value>
        public int Orbits
        {
            get { return (int)GetValue(OrbitsProperty); }
            set { SetValue(OrbitsProperty,value); }
        }

        /// <summary>
        /// 用DependencyProperty的Register方法注册依赖属性OrbitsProperty
        /// </summary>
        public static readonly DependencyProperty OrbitsProperty = DependencyProperty.Register("Orbits",typeof(int),typeof(OrbitPanel),new PropertyMetadata(1,OnorbitsChanged));
        public static void OnorbitsChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
        {
            if ((int)e.NewValue < 1)
            {
                throw new ArgumentException("Orbits must be greater than or equal to 1");
            }
        }

        //The Orbit attached property in the OrbitPanel class
        //Getorbit和Setorbit定义OrbitPanel的附加属性(Attached Property)Orbit
        //Orbit表示控件位于第几个轨道
        public static int Getorbit(DependencyObject obj)
        {
            return (int)obj.GetValue(OrbitProperty);
        }

        public static void Setorbit(DependencyObject obj,int value)
        {
            obj.SetValue(OrbitProperty,value);
        }

        /// <summary>
        /// 依赖属性Orbit利用DependencyProperty提供的Registerattached的方法进行注册
        /// </summary>
        public static readonly DependencyProperty OrbitProperty = DependencyProperty.Registerattached("Orbit",new PropertyMetadata(0));

        private double CalculateOrbitSpacing(Size availableSize)
        {
            double constrainingSize = Math.Min(availableSize.Width,availableSize.Height);
            double space = constrainingSize / 2;
            return space / Orbits;
        }

        private List<UIElement>[] SortElements()
        {
            var list = new List<UIElement>[Orbits];
            for (int i = 0; i < Orbits; i++)
            {
                if (i == Orbits - 1)
                {
                    list[i] = (from UIElement child in Children where Getorbit(child) >= i select child).ToList<UIElement>();
                }
                else
                {
                    list[i] = (from UIElement child in Children where Getorbit(child) == i select child).ToList<UIElement>();
                }
            }
            return list;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            var sortedItems = SortElements();
            double max = 0.0;
            foreach (List<UIElement> orbitItems in sortedItems)
            {
                if (orbitItems.Count > 0)
                {
                    foreach (UIElement element in orbitItems)
                    {
                        element.Measure(availableSize);
                        if (element.DesiredSize.Width > max)
                        {
                            max = element.DesiredSize.Width;
                        }
                        if (element.DesiredSize.Height > max)
                        {
                            max = element.DesiredSize.Height;
                        }
                    }
                }
            }
            Size desiredSize = new Size(max * Orbits * 2,max * Orbits * 2);
            if (Double.IsInfinity(availableSize.Height) || Double.IsInfinity(availableSize.Width))
            {
                return desiredSize;
            }
            else
            {
                return availableSize;
            }
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            var sortedItems = SortElements();
            double orbitSpacing = CalculateOrbitSpacing(finalSize);
            for (int i = 0; i < sortedItems.Length; i++ )
            {
                List<UIElement> orbitItems = sortedItems[i];
                int count = orbitItems.Count;
                if (count > 0)
                {
                    //计算每个轨道的周长
                    double circumference = 2 * Math.PI * orbitSpacing * (i + 1);
                    double slotSize = Math.Min(orbitSpacing,circumference / count);
                    double maxSize = Math.Min(orbitSpacing,slotSize);
                    double angleIncrement = 360 / count;
                    double currentAngle = 0;
                    Point centerPoint = new Point(finalSize.Width / 2,finalSize.Height / 2);

                    for (int j = 0; j < orbitItems.Count; j++)
                    {
                        UIElement element = orbitItems[j];
                        double angle = Math.PI / 180 * (currentAngle - 90);
                        double left = orbitSpacing * (i + 1) * Math.Cos(angle);
                        double top = orbitSpacing * (i + 1) * Math.Sin(angle);
                        Rect finalRect = new Rect(centerPoint.X + left - element.DesiredSize.Width / 2,centerPoint.Y + top - element.DesiredSize.Height / 2,element.DesiredSize.Width,element.DesiredSize.Height);
                        element.Arrange(finalRect);
                        currentAngle += angleIncrement;
                    }
                }
            }
            return base.ArrangeOverride(finalSize);
        }
    }
}
测试代码如下:

<UserControl x:Class="CustomControls.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:clib="clr-namespace:ControlsLib;assembly=ControlsLib"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.Resources>
            <Style targettype="Button">
                <Setter Property="Width" Value="100" />
                <Setter Property="Height" Value="30" />
            </Style>
        </Grid.Resources>
        <clib:OrbitPanel Orbits="3">
            <Button Content="Button 1" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 2" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 3" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 4" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 5" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 6" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 7" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 8" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 9" Background="Orange"
clib:OrbitPanel.Orbit="0" />
            <Button Content="Button 10" Background="Blue"
clib:OrbitPanel.Orbit="1" />
            <Button Content="Button 11" Background="Blue"
clib:OrbitPanel.Orbit="1" />
            <Button Content="Button 12" Background="Blue"
clib:OrbitPanel.Orbit="1" />
            <Button Content="Button 13" Background="Blue"
clib:OrbitPanel.Orbit="1" />
            <Button Content="Button 14" Background="Blue"
clib:OrbitPanel.Orbit="1" />
        </clib:OrbitPanel>
    </Grid>
</UserControl>

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐