wpf瀑布流布局

之前看了很多的WPF瀑布流布局,无奈自己太笨,多次实践都失败了,最后再cnblog中看到一篇关于WinPhone中的瀑布流布局的文章(http://www.cnblogs.com/Smallcode/archive/2012/10/19/2730810.html),受到启发,放到自己的项目中,却还是发现不少问题,没办法,实在是再找不到了,只能硬着头皮试试改了,没想到还成功了。

 如题,这个修复了一些BUG,包括最大化,最小化,及快速拖动窗口时,布局界面不能及时刷新。
  先看一下效果图:

         wpf瀑布流布局_第1张图片

自定义瀑布流控件:

// ***********************************************************************
// Assembly         : ISmart
// Author           : Snail
// Created          : 08-13-2014
//
// Last Modified By : Snail
// Last Modified On : 08-18-2014
// ***********************************************************************
// 
//     Copyright (c) . All rights reserved.
// 
// 自定义瀑布流布局面板,在所有子项宽度都统一的情况的下,实现瀑布流布局
// ***********************************************************************
 
using System;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
 
namespace ISmart.CustomControl
{
    /// 
    /// 自定义瀑布流布局面板
    /// 
    public class CustomPanel : Panel
    {
        #region 构造函数
        /// 
        /// Initializes a new instance of the  class.
        /// 
        public CustomPanel()
        {
            //根据列数,实例化用来存放每列高度的数组
            ColumnHeight = new double[ColumnCount];
        }
 
        #endregion 构造函数
 
        /// 
        /// 每列的高度
        /// 
        public static double[] ColumnHeight;
 
        /// 
        /// 列数
        /// 
        /// The column count.
        public int ColumnCount
        {
            get { return (int)this.GetValue(ColumnCountProperty); }
            set { this.SetValue(ColumnCountProperty, value); }
        }
 
        /// 
        /// The column count property
        /// 
        public static readonly DependencyProperty ColumnCountProperty = DependencyProperty.Register("ColumnCount", typeof(int), typeof(CustomPanel), new PropertyMetadata(PropertyChanged));
 
        /// 
        /// Properties the changed.
        /// 
        /// The sender.
        /// The  instance containing the event data.
        public static void PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            ColumnHeight = new double[(int)e.NewValue];
            if (sender == null || e.NewValue == e.OldValue)
                return;
            sender.SetValue(ColumnCountProperty, e.NewValue);
 
        }
 
        /// 
        /// 当在派生类中重写时,请测量子元素在布局中所需的大小,然后确定  派生类的大小。
        /// 更新当前元素与其子元素的布局,以下处理都属于 测量 处理,并非实际布局
        /// 
        /// 此元素可以赋给子元素的可用大小。可以指定无穷大值,这表示元素的大小将调整为内容的可用大小。
        /// 此元素在布局过程中所需的大小,这是由此元素根据对其子元素大小的计算而确定的。
        protected override Size MeasureOverride(Size availableSize)
        {
            Console.WriteLine(ColumnCount);
            //清空所有列的高度
            for (int i = 0; i < ColumnHeight.Count(); i++)
            {
                ColumnHeight[i] = 0;
            }
            //计算行数
            int indexY = this.Children.Count / ColumnCount;
 
            //计算行数
            if (this.Children.Count % ColumnCount > 0) indexY++;
            //输出
            //Console.WriteLine("总个数:" + Children.Count);
            //Console.WriteLine("行数:"+indexY);
            //第几行
            int flagY = 0;
            //声明一个尺寸,用来存放测量后面板的尺寸
            Size resultSize = new Size(0, 0);
 
            #region 测量值
            //循环所有行
            for (int i = 0; i < indexY; i++)//行
            {
                //计算面板要呈现的宽度
                resultSize.Width = Children[i].DesiredSize.Width * ColumnCount;
                //处理最后一行
                if (i == indexY - 1)
                {
 
                    //剩余内容项个数
                    int residual = Children.Count - i * ColumnCount;
                    //如果集合总数小于列数,那么剩余内容项就是集合总数
                    if (Children.Count <= ColumnCount)
                    {
                        residual = Children.Count;
                    }
                    //循环剩余元素,设置元素呈现大小,计算当前列需要的高度
                    for (int h = 0; h < residual; h++)
                    {
                        //更新当前循环元素的布局
                        Children[ColumnCount * flagY + h].Measure(availableSize);
                        //累加每一列元素的高度
                        ColumnHeight[h] += Children[ColumnCount * flagY + h].DesiredSize.Height;
                        //Console.WriteLine(string.Format("测量高度{1}:{0}", Children[ColumnCount * flagY + h].DesiredSize.Height, ColumnCount * flagY + h));
                    }
                }
                else
                {
 
                    for (int y = 0; y < ColumnCount; y++)
                    {
                        Children[ColumnCount * flagY + y].Measure(availableSize);
                        ColumnHeight[y] += Children[ColumnCount * flagY + y].DesiredSize.Height;
                        //Console.WriteLine(string.Format("测量高度{1}:{0}", Children[ColumnCount * flagY + y].DesiredSize.Height, ColumnCount * flagY + y));
                    }
                    flagY++;
                }
            }
 
            #endregion 测量值
 
            //面板的高度等于所有列中最高的值
            resultSize.Height = ColumnHeight.Max();
            Console.WriteLine(resultSize.Height);
 
            //设置面板呈现的高度
            //如果父元素给子元素提供的是一个无穷的宽,则使用计算的宽度,否则使用父元素的宽
            resultSize.Width =
            double.IsPositiveInfinity(availableSize.Width) ?
            resultSize.Width : availableSize.Width;
 
            //设置面板呈现的高度
            //如果父元素给子元素提供的是一个无穷的高,则使用计算的宽度,否则使用父元素的高
            resultSize.Height =
            double.IsPositiveInfinity(availableSize.Height) ?
            resultSize.Height : availableSize.Height;
            //输出
            //Console.WriteLine(string.Format("Width:{0},Height:{1}", resultSize.Width, resultSize.Height));
            //返回测量尺寸
            return resultSize;
        }
 
        /// 
        /// 在派生类中重写时,请为  派生类定位子元素并确定大小。
        /// 更新当前元素与其子元素的布局,以下处理都属于 实际 处理,元素布局都将基于此
        /// 
        /// 父级中此元素应用来排列自身及其子元素的最终区域。
        /// 所用的实际大小。
        protected override Size ArrangeOverride(Size finalSize)
        {
            //清空所有列的高度
            for (int i = 0; i < ColumnHeight.Count(); i++)
            {
                ColumnHeight[i] = 0;
            }
 
            //计算行数
            int indexY = this.Children.Count / ColumnCount;
            if (this.Children.Count % ColumnCount > 0) indexY++;
 
            //当前行
            int flagY = 0;
 
            //当前行高
            double flagX = 0;
 
            #region 实际值
 
            //循环所有行
            for (int i = 0; i < indexY; i++)
            {
                //元素最终的宽度
                finalSize.Width = Children[i].DesiredSize.Width * ColumnCount;
 
                //处理最后一行
                if (i == indexY - 1)
                {
                    //列宽
                    flagX = 0;
                    //剩余项个数
                    int residual = Children.Count - i * ColumnCount;
                    if (Children.Count <= ColumnCount)
                    {
                        residual = Children.Count;
                    }
 
                    for (int h = 0; h < residual; h++)
                    {
 
                        //Console.WriteLine(string.Format("实际坐标{4}:{0},{1},{2},{3}", flagX, ColumnHeight[h], Children[ColumnCount * i + h].DesiredSize.Width, Children[ColumnCount * i + h].DesiredSize.Height, ColumnCount * flagY + h));
                        Children[ColumnCount * i + h].Arrange(new Rect(new Point(flagX, ColumnHeight[h]), Children[ColumnCount * i + h].DesiredSize));
                        ColumnHeight[h] += Children[ColumnCount * i + h].DesiredSize.Height;
                        flagX += Children[ColumnCount * i + h].DesiredSize.Width;
                    }
                }
                else
                {
                    flagX = 0;
                    for (int y = 0; y < ColumnCount; y++)
                    {
                        //Console.WriteLine(string.Format("实际坐标{4}:{0},{1},{2},{3}", flagX, i * ColumnHeight[y], Children[ColumnCount * i + y].DesiredSize.Width, Children[ColumnCount * i + y].DesiredSize.Height, ColumnCount * flagY + y));
                        Children[ColumnCount * flagY + y].Arrange(new Rect(new Point(flagX, ColumnHeight[y]), Children[ColumnCount * i + y].DesiredSize));
                        ColumnHeight[y] += Children[ColumnCount * flagY + y].DesiredSize.Height;
                        flagX += Children[ColumnCount * flagY + y].DesiredSize.Width;
                    }
                    flagY++;
                }
            }
            //finalSize.Height = ColumnHeight.Max();
 
            #endregion 测量值
 
            return finalSize;
        }
    }
}
XAML代码:


            
                
                    
                    
            
后台代码:

        //窗体尺寸改变时,改变瀑布流容器的列
        /// 
        /// Windows the size changed.
        /// 
        /// The sender.
        /// The  instance containing the event data.
        public void WindowSizeChanged(object sender, System.Windows.RoutedEventArgs e)
        {
            if (LstSearch.Items.Count <= 0)
            {
                return;
            }
            Window currentWindow = Window.GetWindow(this);
            var width = currentWindow.ActualWidth;
            int columnNum = (int)width / 240;
            //只在列数改变的情况下赋值,有效减少CustomPanel重绘次数
            if (columnNum != _columnCount)
            {
                _columnCount = columnNum;
                _imgsPanel.ColumnCount = columnNum;
                //手动触发CustomPanel的Measure方法
                //让窗体在最大化,最小化的情况下重绘
                _imgsPanel.Measure(_imgsPanel.DesiredSize);
            }
        }


你可能感兴趣的:(wpf瀑布流布局)