zoukankan      html  css  js  c++  java
  • Silverlight:利用Panel实现自定义布局

    虽然Silverlight提供了几种基本的布局方式,比如Canvas,Grid,StackPanel,Border...,但有时候可能仍然会觉得不够用。

    这时候我们可以通过继承Panel,并重写MeasureOverride 和ArrangeOverride 方法,以实现自己的布局,事实上Canvas,Grid,StackPanel就是继承自Panel,并自行实现这二个方法实现的。

    布局过程中,有二个关键的步骤:测量和排列子元素,正好对应MeasureOverride 与ArrangeOverride 二个方法.

    MeasureOverride 中必须遍历所有子元素,并调用子元素的Measure 方法,以便让布局系统确定每个子元素的 DesiredSize(即:子元素自身希望占据的空间大小),这是在调用 Measure 之后在系统内部发生的(开发人员无法干预),该值将在后面排列过程期间使用。 

    ArrangeOverride 中同样也必须遍历所有子元素,并调用子元素的Arrange方法,以便让布局系统会告诉 Panel 可用于它及其子元素的 finalSize(即最终实际占据的空间大小)。

    下面的示例,修改自SL3的官方文档,它将一个400 * 400大小的Panel,划分成16个小单元格(每个正好100*100),放置在其中的元素,将自动依次填充到这些单元格的正中央,如果元素多于16个,将被忽略。

    MyPanel.cs代码:

    代码
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System;

    namespace CustomPanel
    {
        
    public class MyPanel : Panel
        {
            
    const int _CellSize = 100;//每个单元格宽高均为100
            const int _CellCount = 4;//4*4的正方形单元格

            
    public MyPanel() : base()
            {

            }

            
    /// <summary>
            
    /// 先测量
            
    /// </summary>
            
    /// <param name="availableSize"></param>
            
    /// <returns></returns>
            protected override Size MeasureOverride(Size availableSize)
            {
                
    for (int i = 0; i < this.Children.Count; i++)
                {
                    
    if (i < _CellCount * _CellCount)
                    {
                        
    this.Children[i].Measure(new Size(_CellSize, _CellSize));
                    }
                    
    else
                    {
                        
    //this.Children[i].Measure(new Size(0, 0));//超出元素不分配空间,其实这行也可以不要,因为ArrangeOverride中对超出元素最终并未安排空间
                    }
                }
                
    return availableSize;            
            }

            
    /// <summary>
            
    /// 再排列
            
    /// </summary>
            
    /// <param name="finalSize"></param>
            
    /// <returns></returns>
            protected override Size ArrangeOverride(Size finalSize)
            {           
                
    for (int i = 0; i < this.Children.Count; i++)
                {
                    
    if (i < _CellCount * _CellCount)
                    {
                        Point cellOrigin 
    = GetCellOriginPoint(i, _CellCount, new Size(_CellSize, _CellSize));
                        
    double dw = this.Children[i].DesiredSize.Width;
                        
    double dh = this.Children[i].DesiredSize.Height;
                        
    this.Children[i].Arrange(new Rect(cellOrigin.X + (_CellSize - dw) / 2, cellOrigin.Y + (_CellSize - dh) / 2, dw, dh));//每个子元素都放在单元格正中央
                    }
                    
    else
                    {
                        
    this.Children[i].Arrange(new Rect(0000));//超出的元素,不安排空间(即不显示)
                    }
                }
                
    return new Size(_CellSize * _CellCount, _CellSize * _CellCount);

                
    //下面这二行,演示了如何将可视区域设置为仅100*100大小
                
    //this.Clip = new RectangleGeometry() { Rect = new Rect(0,0,100,100) };
                
    //return new Size(100, 100);
            }

            
    /// <summary>
            
    /// 取得每个单元格的(左上)起始点坐标
            
    /// </summary>
            
    /// <param name="cellIndex"></param>
            
    /// <param name="cellCount"></param>
            
    /// <param name="itemSize"></param>
            
    /// <returns></returns>
            protected Point GetCellOriginPoint(int cellIndex, int cellCount, Size itemSize)
            {
                
    int row = (int)Math.Floor(cellIndex / cellCount);
                
    int col = cellIndex - cellCount * row;
                Point origin 
    = new Point(itemSize.Width * col, itemSize.Height * row);
                
    return origin;
            }        


        }
    }

    测试页MainPage.Xaml

    代码
    <UserControl x:Class="CustomPanel.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:l
    ="clr-namespace:CustomPanel"
        xmlns:mc
    ="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        mc:Ignorable
    ="d" d:DesignWidth="640" d:DesignHeight="480">
        
    <l:MyPanel x:Name="myPnl" Background="#FFEFEFEF" HorizontalAlignment="Center" VerticalAlignment="Center" >
            
    <Button Content="01"></Button>
            
    <Button Content="02"></Button>
            
    <TextBlock Text="03"></TextBlock>
            
    <Button Content="04"></Button>
            
    <Button Content="05"></Button>
            
    <TextBox Text="06"></TextBox>
            
    <Button Content="07"></Button>
            
    <Button Content="08"></Button>
            
    <Button Content="09"></Button>
            
    <Button Content="10"></Button>
            
    <Button Content="11"></Button>
            
    <Button Content="12"></Button>
            
    <TextBlock Text="13"></TextBlock>
            
    <Button Content="14"></Button>
            
    <Button Content="15"></Button>
            
    <Button Content="16"></Button>
            
    <Button Content="17"></Button>
        
    </l:MyPanel>
    </UserControl>

    运行效果图:

    上面我们把Panel的尺寸定死为400 * 400了,如果想实现自由扩展,还要稍微再修改一下:

    自由扩展的4 * 4格Panel
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System;

    namespace CustomPanel
    {
        
    public class MyPanel : Panel
        {
            
    int _CellHeight = 100;//每个单元格的高度(初始为100)
            int _CellWidth = 100;//每个单元格的宽度(初始为100)
            const int _CellCount = 4;//4*4的正方形单元格

            
    public MyPanel() : base()
            {

            }

            
    /// <summary>
            
    /// 先测量
            
    /// </summary>
            
    /// <param name="availableSize"></param>
            
    /// <returns></returns>
            protected override Size MeasureOverride(Size availableSize)
            {
                
    //重新每个单元格的尺寸
                _CellWidth = (int)availableSize.Width / _CellCount;
                _CellHeight 
    = (int)availableSize.Height / _CellCount;

                
    for (int i = 0; i < this.Children.Count; i++)
                {
                    
    if (i < _CellCount * _CellCount)
                    {
                        
    this.Children[i].Measure(new Size(_CellWidth, _CellHeight));
                    }
                    
    else
                    {
                        
    //this.Children[i].Measure(new Size(0, 0));//超出元素不分配空间,其实这行也可以不要,因为ArrangeOverride中对超出元素最终并未安排空间
                    }
                }
                
    return availableSize;            
            }

            
    /// <summary>
            
    /// 再排列
            
    /// </summary>
            
    /// <param name="finalSize"></param>
            
    /// <returns></returns>
            protected override Size ArrangeOverride(Size finalSize)
            {           
                
    for (int i = 0; i < this.Children.Count; i++)
                {
                    
    if (i < _CellCount * _CellCount)
                    {
                        Point cellOrigin 
    = GetCellOriginPoint(i, _CellCount, new Size(_CellWidth, _CellHeight));
                        
    double dw = this.Children[i].DesiredSize.Width;
                        
    double dh = this.Children[i].DesiredSize.Height;
                        
    this.Children[i].Arrange(new Rect(cellOrigin.X + (_CellWidth - dw) / 2, cellOrigin.Y + (_CellHeight - dh) / 2, dw, dh));//每个子元素都放在单元格正中央
                    }
                    
    else
                    {
                        
    this.Children[i].Arrange(new Rect(0000));//超出的元素,不安排空间(即不显示)
                    }
                }
                
    return new Size(_CellWidth * _CellCount, _CellHeight * _CellCount);

                
    //下面这二行,演示了如何将可视区域设置为仅100*100大小
                
    //this.Clip = new RectangleGeometry() { Rect = new Rect(0,0,100,100) };
                
    //return new Size(100, 100);
            }

            
    /// <summary>
            
    /// 取得每个单元格的(左上)起始点坐标
            
    /// </summary>
            
    /// <param name="cellIndex"></param>
            
    /// <param name="cellCount"></param>
            
    /// <param name="itemSize"></param>
            
    /// <returns></returns>
            protected Point GetCellOriginPoint(int cellIndex, int cellCount, Size itemSize)
            {
                
    int row = (int)Math.Floor(cellIndex / cellCount);
                
    int col = cellIndex - cellCount * row;
                Point origin 
    = new Point(itemSize.Width * col, itemSize.Height * row);
                
    return origin;
            }        


        }
    }

    CodeProject上还有几篇扩展Panel的不错文章:

    http://www.codeproject.com/KB/WPF/Panels.aspx 鱼眼效果布局的实现
    http://www.codeproject.com/KB/silverlight/advancedcanvas.aspx 9宫格的实现
    这一篇更强大:

    http://dotnet.org.za/rudi/archive/2008/04/15/why-wpf-rocks-custom-layout-panel-showcase.aspx

    作者:菩提树下的杨过
    出处:http://yjmyzz.cnblogs.com
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    都是CSS惹的祸
    Ruby简介
    网络攻击利用DedeCms漏洞
    ASP.NET验证技术详解
    一个低级错误引发的血案
    FCKeditor配置和精简【附源码】
    邮件发送详解
    Timer定时器的设计实例详解
    常用的加密算法MD5、SHA1
    JS日历控件集合附效果图、源代码
  • 原文地址:https://www.cnblogs.com/yjmyzz/p/1631163.html
Copyright © 2011-2022 走看看