最近在用wpf做一个metro风格的程序,需要用到win8风格的布局容器,只能自己写一个了。效果如下

用法 : <local:TilePanel
                         TileMargin="1"
                         Orientation="Horizontal"
                         TileCount="4" >

  //todo 放置内容

  //local:TilePanel.WidthPix="1" 控制宽度倍率
      //local:TilePanel.HeightPix="2"控制高度倍率

</local:TilePanel>

下面附上源码。

    /// <summary>
    /// TilePanel
    /// 瀑布流布局
    /// </summary>
    public class TilePanel : Panel
    {
        #region 枚举         private enum OccupyType
        {
            NONE,
            WIDTHHEIGHT,
            OVERFLOW
        }         #endregion         #region 属性         /// <summary>
        /// 容器内元素的高度
        /// </summary>
        public int TileHeight
        {
            get { return (int)GetValue(TileHeightProperty); }
            set { SetValue(TileHeightProperty, value); }
        }
        /// <summary>
        /// 容器内元素的高度
        /// </summary>
        public static readonly DependencyProperty TileHeightProperty =
            DependencyProperty.Register("TileHeight", typeof(int), typeof(TilePanel), new FrameworkPropertyMetadata(100, FrameworkPropertyMetadataOptions.AffectsMeasure));
        /// <summary>
        /// 容器内元素的宽度
        /// </summary>
        public int TileWidth
        {
            get { return (int)GetValue(TileWidthProperty); }
            set { SetValue(TileWidthProperty, value); }
        }
        /// <summary>
        /// 容器内元素的宽度
        /// </summary>
        public static readonly DependencyProperty TileWidthProperty =
            DependencyProperty.Register("TileWidth", typeof(int), typeof(TilePanel), new FrameworkPropertyMetadata(100, FrameworkPropertyMetadataOptions.AffectsMeasure));
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static int GetWidthPix(DependencyObject obj)
        {
            return (int)obj.GetValue(WidthPixProperty);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetWidthPix(DependencyObject obj, int value)
        {
            if (value > 0)
            {
                obj.SetValue(WidthPixProperty, value);
            }
        }
        /// <summary>
        /// 元素的宽度比例,相对于TileWidth
        /// </summary>
        public static readonly DependencyProperty WidthPixProperty =
            DependencyProperty.RegisterAttached("WidthPix", typeof(int), typeof(TilePanel), new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsParentMeasure));
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static int GetHeightPix(DependencyObject obj)
        {
            return (int)obj.GetValue(HeightPixProperty);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="value"></param>
        public static void SetHeightPix(DependencyObject obj, int value)
        {
            if (value > 0)
            {
                obj.SetValue(HeightPixProperty, value);
            }
        }
        /// <summary>
        /// 元素的高度比例,相对于TileHeight
        /// </summary>
        public static readonly DependencyProperty HeightPixProperty =
            DependencyProperty.RegisterAttached("HeightPix", typeof(int), typeof(TilePanel), new FrameworkPropertyMetadata(1, FrameworkPropertyMetadataOptions.AffectsParentMeasure));
        /// <summary>
        /// 排列方向
        /// </summary>
        public Orientation Orientation
        {
            get { return (Orientation)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }
        /// <summary>
        /// 排列方向
        /// </summary>
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register("Orientation", typeof(Orientation), typeof(TilePanel), new FrameworkPropertyMetadata(Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure));
        /// <summary>
        /// 格子数量
        /// </summary>
        public int TileCount
        {
            get { return (int)GetValue(TileCountProperty); }
            set { SetValue(TileCountProperty, value); }
        }
        /// <summary>
        /// 格子数量
        /// </summary>
        public static readonly DependencyProperty TileCountProperty =
            DependencyProperty.Register("TileCount", typeof(int), typeof(TilePanel), new PropertyMetadata(4));
        /// <summary>
        /// Tile之间的间距
        /// </summary>
        public Thickness TileMargin
        {
            get { return (Thickness)GetValue(TileMarginProperty); }
            set { SetValue(TileMarginProperty, value); }
        }
        /// <summary>
        /// Tile之间的间距
        /// </summary>
        public static readonly DependencyProperty TileMarginProperty =
            DependencyProperty.Register("TileMargin", typeof(Thickness), typeof(TilePanel), new FrameworkPropertyMetadata(new Thickness(2), FrameworkPropertyMetadataOptions.AffectsMeasure));
        /// <summary>
        /// 最小的高度比例
        /// </summary>
        private int MinHeightPix { get; set; }
        /// <summary>
        /// 最小的宽度比例
        /// </summary>
        private int MinWidthPix { get; set; }         #endregion         #region 方法         private Dictionary<string, Point> Maps { get; set; }
        private OccupyType SetMaps(Point currentPosition, Size childPix)
        {
            var isOccupy = OccupyType.NONE;             if (currentPosition.X + currentPosition.Y != 0)
            {
                if (this.Orientation == System.Windows.Controls.Orientation.Horizontal)
                {
                    isOccupy = this.IsOccupyWidth(currentPosition, childPix);
                }
                else
                {
                    isOccupy = this.IsOccupyHeight(currentPosition, childPix);
                }
            }             if (isOccupy == OccupyType.NONE)
            {
                for (int i = 0; i < childPix.Width; i++)
                {
                    for (int j = 0; j < childPix.Height; j++)
                    {
                        this.Maps[string.Format("x_{0}y_{1}", currentPosition.X + i, currentPosition.Y + j)] = new Point(currentPosition.X + i, currentPosition.Y + j);
                    }
                }
            }             return isOccupy;
        }
        private OccupyType IsOccupyWidth(Point currentPosition, Size childPix)
        {
            //计算当前行能否放下当前元素
            if (this.TileCount - currentPosition.X - childPix.Width < 0)
            {
                return OccupyType.OVERFLOW;
            }             for (int i = 0; i < childPix.Width; i++)
            {
                if (this.Maps.ContainsKey(string.Format("x_{0}y_{1}", currentPosition.X + i, currentPosition.Y)))
                {
                    return OccupyType.WIDTHHEIGHT;
                }
            }             return OccupyType.NONE;
        }
        private OccupyType IsOccupyHeight(Point currentPosition, Size childPix)
        {
            //计算当前行能否放下当前元素
            if (this.TileCount - currentPosition.Y - childPix.Height < 0)
            {
                return OccupyType.OVERFLOW;
            }             for (int i = 0; i < childPix.Height; i++)
            {
                if (this.Maps.ContainsKey(string.Format("x_{0}y_{1}", currentPosition.X, currentPosition.Y + i)))
                {
                    return OccupyType.WIDTHHEIGHT;
                }
            }             return OccupyType.NONE;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="finalSize"></param>
        /// <returns></returns>
        protected override Size ArrangeOverride(Size finalSize)
        {
            Size childPix = new Size();
            Point childPosition = new Point();
            Point? lastChildPosition = null;
            OccupyType isOccupy = OccupyType.NONE;
            FrameworkElement child;             this.Maps = new Dictionary<string, Point>();
            for (int i = 0; i < this.Children.Count; )
            {
                child = this.Children[i] as FrameworkElement;
                childPix.Width = TilePanel.GetWidthPix(child);
                childPix.Height = TilePanel.GetHeightPix(child);                 if (this.Orientation == System.Windows.Controls.Orientation.Vertical)
                {
                    if (childPix.Height > this.TileCount)
                    {
                        childPix.Height = this.TileCount;
                    }
                }
                else
                {
                    if (childPix.Width > this.TileCount)
                    {
                        childPix.Width = this.TileCount;
                    }
                }
                isOccupy = this.SetMaps(childPosition, childPix);
                //换列
                if (isOccupy == OccupyType.WIDTHHEIGHT)
                {
                    if (lastChildPosition == null) lastChildPosition = childPosition;
                    if (this.Orientation == System.Windows.Controls.Orientation.Horizontal)
                    {
                        childPosition.X += this.MinWidthPix;
                    }
                    else
                    {
                        childPosition.Y += this.MinHeightPix;
                    }
                }
                //换行
                else if (isOccupy == OccupyType.OVERFLOW)
                {
                    if (lastChildPosition == null) lastChildPosition = childPosition;
                    if (this.Orientation == System.Windows.Controls.Orientation.Horizontal)
                    {
                        childPosition.X = 0;
                        childPosition.Y += this.Maps[string.Format("x_{0}y_{1}", childPosition.X, childPosition.Y)].Y;
                        //childPosition.Y++;//= this.MinHeightPix;
                    }
                    else
                    {
                        childPosition.Y = 0;
                        childPosition.X += this.Maps[string.Format("x_{0}y_{1}", childPosition.X, childPosition.Y)].X;
                        //childPosition.X++;//= this.MinWidthPix;
                    }
                }
                else
                {
                    i++;
                    child.Arrange(new Rect(childPosition.X * this.TileWidth + Math.Floor(childPosition.X / this.MinWidthPix) * (this.TileMargin.Left + this.TileMargin.Right),
                                           childPosition.Y * this.TileHeight + Math.Floor(childPosition.Y / this.MinHeightPix) * (this.TileMargin.Top + this.TileMargin.Bottom),
                                           child.DesiredSize.Width, child.DesiredSize.Height));
                    if (lastChildPosition != null)
                    {
                        childPosition = (Point)lastChildPosition;
                        lastChildPosition = null;
                    }
                    else
                    {
                        if (this.Orientation == System.Windows.Controls.Orientation.Horizontal)
                        {
                            childPosition.X += childPix.Width;
                            if (childPosition.X == this.TileCount)
                            {
                                childPosition.X = 0;
                                childPosition.Y++;
                            }
                        }
                        else
                        {
                            childPosition.Y += childPix.Height;
                            if (childPosition.Y == this.TileCount)
                            {
                                childPosition.Y = 0;
                                childPosition.X++;
                            }
                        }
                    }
                }
            }             return finalSize;
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="constraint"></param>
        /// <returns></returns>
        protected override Size MeasureOverride(Size constraint)
        {
            int childWidthPix, childHeightPix, maxRowCount = 0;             if (this.Children.Count == 0) return new Size();
            //遍历孩子元素
            foreach (FrameworkElement child in this.Children)
            {
                childWidthPix = TilePanel.GetWidthPix(child);
                childHeightPix = TilePanel.GetHeightPix(child);                 if (this.MinHeightPix == 0) this.MinHeightPix = childHeightPix;
                if (this.MinWidthPix == 0) this.MinWidthPix = childWidthPix;                 if (this.MinHeightPix > childHeightPix) this.MinHeightPix = childHeightPix;
                if (this.MinWidthPix > childWidthPix) this.MinWidthPix = childWidthPix;
            }             foreach (FrameworkElement child in this.Children)
            {
                childWidthPix = TilePanel.GetWidthPix(child);
                childHeightPix = TilePanel.GetHeightPix(child);                 child.Margin = this.TileMargin;
                child.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
                child.VerticalAlignment = System.Windows.VerticalAlignment.Top;                 child.Width = this.TileWidth * childWidthPix + (child.Margin.Left + child.Margin.Right) * ((childWidthPix - this.MinWidthPix) / this.MinWidthPix);
                child.Height = this.TileHeight * childHeightPix + (child.Margin.Top + child.Margin.Bottom) * ((childHeightPix - this.MinHeightPix) / this.MinHeightPix);                 maxRowCount += childWidthPix * childHeightPix;                 child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
            }             if (this.TileCount <= 0) throw new ArgumentOutOfRangeException();
            //if (this.MinWidthPix == 0) this.MinWidthPix = 1;
            //if (this.MinHeightPix == 0) this.MinHeightPix = 1;
            if (this.Orientation == Orientation.Horizontal)
            {
                this.Width = constraint.Width = this.TileCount * this.TileWidth + this.TileCount / this.MinWidthPix * (this.TileMargin.Left + this.TileMargin.Right);
                double heightPix = Math.Ceiling((double)maxRowCount / this.TileCount);
                if (!double.IsNaN(heightPix))
                    constraint.Height = heightPix * this.TileHeight + heightPix / this.MinHeightPix * (this.TileMargin.Top + this.TileMargin.Bottom);
            }
            else
            {
                this.Height = constraint.Height = this.TileCount * this.TileHeight + this.TileCount / this.MinHeightPix * (this.TileMargin.Top + this.TileMargin.Bottom);
                double widthPix = Math.Ceiling((double)maxRowCount / this.TileCount);
                if (!double.IsNaN(widthPix))
                    constraint.Width = widthPix * this.TileWidth + widthPix / this.MinWidthPix * (this.TileMargin.Left + this.TileMargin.Right);
            }             return constraint;
        }         #endregion
    }

WPF中的瀑布流布局(TilePanel)控件的更多相关文章

  1. WPF中不规则窗体与WindowsFormsHost控件的兼容问题完美解决方案

    首先先得瑟一下,有关WPF中不规则窗体与WindowsFormsHost控件不兼容的问题,网上给出的解决方案不能满足所有的情况,是有特定条件的,比如  WPF中不规则窗体与WebBrowser控件的兼 ...

  2. WPF中不规则窗体与WebBrowser控件的兼容问题解决办法

    原文:WPF中不规则窗体与WebBrowser控件的兼容问题解决办法 引言 这几天受委托开发一个网络电视项目,要求初步先使用内嵌网页形式实现视频播放和选单,以后再考虑将网页中的所有功能整合进桌面程序. ...

  3. WPF 中动态创建和删除控件

    原文:WPF 中动态创建和删除控件 动态创建控件 1.容器控件.RegisterName("Name",要注册的控件)   //注册控件 2.容器控件.FindName(" ...

  4. 封装:WPF中可以绑定的BindPassWord控件

    原文:封装:WPF中可以绑定的BindPassWord控件 一.目的:本身自带的PassWord不支持绑定 二.Xaml部分 <UserControl x:Class="HeBianG ...

  5. WPF 中动态创建、删除控件,注册控件名字,根据名字查找控件

    动态创建控件 1.容器控件.RegisterName("Name",要注册的控件)   //注册控件 2.容器控件.FindName("Name") as  控 ...

  6. WPF中增加Month Calendar月历控件

    XAML代码:(这里使用了codeproject.com网站上的一个Dll,你可以在这里下载它:http://www.codeproject.com/cs/miscctrl/MonthCalendar ...

  7. WPF中实现多选ComboBox控件

    在WPF中实现带CheckBox的ComboBox控件,让ComboBox控件可以支持多选. 将ComboBox的ItemsSource属性Binding到一个Book的集合, public clas ...

  8. 在WPF中的Canvas上实现控件的拖动、缩放

    如题,项目中需要实现使用鼠标拖动.缩放一个矩形框,WPF中没有现成的,那就自己造一个轮子:) 造轮子前先看看Windows自带的画图工具中是怎样做的,如下图: 在被拖动的矩形框四周有9个小框,可以从不 ...

  9. WPF中Expander的用法和控件模板详解

    一.Expander的用法 在WPF中,Expander是一个很实用的复合控件,可以很方便的实现下拉菜单和导航栏等功能.先介绍简单的用法,而后分析他的控件模板. <Window.Resource ...

随机推荐

  1. 把Flume的Source设置为 Spooling directory source

    把Flume的Source设置为 Spooling directory source,在设定的目录下放置需要读取的文件,一些文件在读取过程中会报错. 文件格式和报错如下: 实验一 读取汉子和“:&qu ...

  2. hdu-5701 中位数计数(中位数)

    题目链接: 中位数计数 Problem Description   中位数定义为所有值从小到大排序后排在正中间的那个数,如果值有偶数个,通常取最中间的两个数值的平均数作为中位数. 现在有nn个数,每个 ...

  3. 洛谷P1717 钓鱼

    P1717 钓鱼 41通过 116提交 题目提供者该用户不存在 标签贪心 难度提高+/省选- 提交该题 讨论 题解 记录 最新讨论 暂时没有讨论 题目描述 话说发源于小朋友精心设计的游戏被电脑组的童鞋 ...

  4. 深入理解ThreadLocal(转)(2015年06月11日)

    注明:转自:http://my.oschina.net/clopopo/blog/149368 学习一个东西首先要知道为什么要引入它,就是我们能用它来干什么.所以我们先来看看ThreadLocal对我 ...

  5. DWZ (JUI) 教程 dwz框架 刷新dialog解决方案

    在DWZ中进行ajax表单提交后,通过回调函数来返回状态结果,以及返回是否需要刷新父页的navTabId.       DWZ给我们提供了两个回调函数,一个是子窗口为navTab的navTabAjax ...

  6. 英特尔实感SDK 代码示例

    原文地址 摘要 本套代码示例针对巴西英特尔实感动手实验室创建,旨在帮助参与人员了解如何使用英特尔® 实感™ 软件开发套件. 12 个示例使用 C# SDK 包装程序,提供了简单的基于控制台的应用,支持 ...

  7. 北大ACM(POJ1009-Edge Detection)

    Question:http://poj.org/problem?id=1009问题点:RLE编码. Memory: 648K Time: 547MS Language: C++ Result: Acc ...

  8. WIN7实用的运行命令

    运行命令主要是DOS操作系统的运行方式.为方便用户的操作,微软公司将一些常用的命令,如DIR,CD等命令全部集成在系统里面:存放这些内部命令的文件是“Command”(文件后缀.com).它与IO.s ...

  9. JQuery 动态添加onclick事件

    $('#div_id').click(function(){ show(1,2,this); });

  10. .NET调用Java写的WebService

    最近遇到一个用.net调用java写的webservice的应用,对方程序员提供了一个后缀为wsdl的文件,这个跟.Net里面生成的wsdl文件差不多,起初没什么概念就查了点资料,知道可以将这个wsd ...