WPF自定义布局--瀑布布局

16 篇文章 0 订阅

目录

引用

C#核心代码实现

XAML核心代码实现

效果如下:

所有代码

C#:

XAML:


引用

提一下瀑布布局的需求,就是打个比方说,我有个三列的冒泡排序的留言板,从下往上冒泡的,但是每次都想要显示在最短的那一列下面,每次最新的冒泡就显示在最短的那一列后面,实现方法如下。

C#核心代码实现

主要是写一个类继承Panel,进行重写里面的方法即可

 // 测量
 protected override Size MeasureOverride(Size availableSize)
 {
     double total_y = 0; // 累计高度
     // 遍历所有的子项
     double per_width = (availableSize.Width - ColumnSpace * 2) / 3;
     foreach (UIElement item in this.InternalChildren)
     {
         item.Measure(new Size(per_width, availableSize.Height));
         total_y += item.DesiredSize.Height;
     }
     return new Size(availableSize.Width, total_y);
 }

 // 排列
 protected override Size ArrangeOverride(Size finalSize)
 {
     double offset_y = 0, offset_x = 0;
     double per_width = (finalSize.Width - ColumnSpace * 2) / 3;
     List<Test> testList = new List<Test>();
     for (int i = 0; i < this.InternalChildren.Count; i++)
     {
         UIElement item = this.InternalChildren[i];
         // 前三个 肯定是从 0 0 开始 每次都是1/3的宽度 第一行
         if (i == 0)
         {
             item.Arrange(new Rect(offset_x, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
             testList.Add(new Test { ValueX = 0, TotalColumn = item.DesiredSize.Height });
         }
         else if (i == 1)
         {
             item.Arrange(new Rect(per_width, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
             testList.Add(new Test { ValueX = per_width, TotalColumn = item.DesiredSize.Height });
         }
         else if (i == 2)
         {
             item.Arrange(new Rect(per_width * 2, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
             testList.Add(new Test { ValueX = per_width * 2, TotalColumn = item.DesiredSize.Height });
         }
         else
         {
             // 设置一个最大的值,无限大的值,然后下面进行选出最小的一直值,然后进行判断
             double minC = 10000;
             foreach (var m in testList)
             {
                 minC = Math.Min(minC, m.TotalColumn);
             }
             Test test = new Test() { TotalColumn = minC};
             testList.ForEach(f =>
             {
                 if(test.TotalColumn == f.TotalColumn)
                 {
                     test.ValueX = f.ValueX;
                 }
             });
             // 获取到最短的那一列,然后获取坐标,在那渲染即可
             item.Arrange(new Rect(test.ValueX, test.TotalColumn, per_width, item.DesiredSize.Height));
             testList.ForEach( f => { 
                 if(f.ValueX == test.ValueX)
                 {
                     f.TotalColumn += item.DesiredSize.Height;
                 }
             });
         }
     }
     return base.ArrangeOverride(finalSize);
 }

XAML核心代码实现

<!--引用写好的类-->
<Grid>
  <local:XHPanel ColumnSpace="2" RowSpace="2">
    <Border Background="Gray">
      <TextBlock Text="B1B1BB11BB1B1B1B1B11B11BB1B1BB11BB1B1B1B1B11B11B" FontSize="20" TextWrapping="Wrap"/>
    </Border>
    <Button Content="B2" Height="20"/>
    <Button Content="B2" Height="90"/>
    <Button Content="B2" Height="90"/>
    <Button Content="B2" Height="90"/>
  </local:XHPanel>
</Grid>

效果如下:

所有代码

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;

namespace XH.LayoutLesson
{
    /// <summary>
    /// 瀑布布局
    /// </summary>
    public class XHPanel : Panel
    {
        // 空隙
        private double _rowSpace = 0;

        public double RowSpace
        {
            get { return _rowSpace; }
            set
            {
                _rowSpace = value;
                // 自动刷新UI
                this.InvalidateVisual();
            }
        }

        private double _columnSpace = 0;

        public double ColumnSpace
        {
            get { return _columnSpace; }
            set
            {
                _columnSpace = value;
                // 重新布局
                this.InvalidateVisual();
            }
        }


        // 测量
        protected override Size MeasureOverride(Size availableSize)
        {
            double total_y = 0; // 累计高度
            // 遍历所有的子项
            double per_width = (availableSize.Width - ColumnSpace * 2) / 3;
            foreach (UIElement item in this.InternalChildren)
            {
                item.Measure(new Size(per_width, availableSize.Height));
                total_y += item.DesiredSize.Height;
            }
            return new Size(availableSize.Width, total_y);
        }
        // 排列
        protected override Size ArrangeOverride(Size finalSize)
        {
            double offset_y = 0, offset_x = 0;
            double per_width = (finalSize.Width - ColumnSpace * 2) / 3;
            double maxHeight = 0;
            List<Test> testList = new List<Test>();
            for (int i = 0; i < this.InternalChildren.Count; i++)
            {
                UIElement item = this.InternalChildren[i];
                if (i == 0)
                {
                    item.Arrange(new Rect(offset_x, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
                    testList.Add(new Test { ValueX = 0, TotalColumn = item.DesiredSize.Height });
                }
                else if (i == 1)
                {
                    item.Arrange(new Rect(per_width, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
                    testList.Add(new Test { ValueX = per_width, TotalColumn = item.DesiredSize.Height });
                }
                else if (i == 2)
                {
                    item.Arrange(new Rect(per_width * 2, (offset_y + RowSpace), per_width, item.DesiredSize.Height));
                    testList.Add(new Test { ValueX = per_width * 2, TotalColumn = item.DesiredSize.Height });
                }
                else
                {
                    double minC = 10000;
                    foreach (var m in testList)
                    {
                        minC = Math.Min(minC, m.TotalColumn);
                    }
                    Test test = new Test() { TotalColumn = minC};
                    testList.ForEach(f =>
                    {
                        if(test.TotalColumn == f.TotalColumn)
                        {
                            test.ValueX = f.ValueX;
                        }
                    });
                    item.Arrange(new Rect(test.ValueX, test.TotalColumn, per_width, item.DesiredSize.Height));
                    testList.ForEach( f => { 
                        if(f.ValueX == test.ValueX)
                        {
                            f.TotalColumn += item.DesiredSize.Height;
                        }
                    });
                }
            }
            return base.ArrangeOverride(finalSize);
        }
    }
    class Test
    {
        public double ValueX { get; set; } // X坐标
        public double TotalColumn { get; set; } // 列总高度
    }
}

XAML:

<Window x:Class="XH.LayoutLesson.TestWindow"
        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:local="clr-namespace:XH.LayoutLesson"
        mc:Ignorable="d" FontSize="50"
        Title="TestWindow" Height="450" Width="800">
    <Grid>
        <local:XHPanel ColumnSpace="2" RowSpace="2">
            <Border Background="Gray">
                <TextBlock 
                  Text="B1B1BB11BB1B1B1111111111111111111111B1B11B11BB1B1BB11BB1B1B1B1B11B11B" 
                  FontSize="20" TextWrapping="Wrap"/>
            </Border>
            <Button Content="B1" Height="40"/>
            <Button Content="B2" Height="90"/>
            <Button Content="B3" Height="90"/>
            <Button Content="B4" Height="90"/>
        </local:XHPanel>
    </Grid>
</Window>

需要完整代码可以在本合集置顶博客看我的代码路径,可以进行学习。

  • 8
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值