基于WPF实现瀑布流控件
wpF 实现瀑布流控件
框架支持.NET4 至 .NET8;
Visual Studio 2022;
需求详见 ISSUE

实现代码
1)新增 WaterfallPanel.cs 代码如下:
WaterfallPanel的自定义控件,继承自VirtualizingPanel。WaterfallPanel控件实现了瀑布流布局,即将多个子元素按照一定规则排列在面板中。该控件具有Columns和Spacing两个依赖属性,分别表示列数和每个子控件之间的间距。MeasureOverride用于测量和排列子控件。在WaterfallPanel的MeasureOverride方法中,先清除了列高的记录,然后计算出每一列的高度并保存在一个List中。接着,遍历所有子控件,将它们测量并按规则排列在面板中,同时更新列高和面板的大小。AddChild方法向面板中添加子控件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Windows;
namespace WPFDevelopers.Controls
{
public class WaterfallPanel : VirtualizingPanel
{
private List<double> columnHeights = new List<double>();
protected override Size MeasureOverride(Size availableSize)
{
columnHeights.Clear();
var panelDesiredSize = new Size(0, 0);
columnHeights = new double[Columns].ToList();
double currentX = 0;
var width = availableSize.Width / Columns - (Columns * Spacing);
for (int i = 0; i < InternalChildren.Count; i++)
{
var child = InternalChildren[i] as FrameworkElement;
if (child == null)
continue;
child.Measure(availableSize);
child.Width = width;
int columnIndex = i % Columns;
double x = columnIndex != 0 ? currentX + Spacing : 0;
double y = columnHeights[columnIndex];
if (i >= Columns)
y = y + Spacing;
var size = new Size(width, child.DesiredSize.Height);
child.Arrange(new Rect(new Point(x, y), size));
panelDesiredSize.Width = Math.Max(panelDesiredSize.Width, x + child.DesiredSize.Width);
panelDesiredSize.Height = Math.Max(panelDesiredSize.Height, y + child.DesiredSize.Height);
currentX = x + size.Width;
if (currentX >= Width)
currentX = 0;
columnHeights[columnIndex] += child.DesiredSize.Height + (i >= Columns ? Spacing : 0);
}
return panelDesiredSize;
}
public void AddChild(UIElement element)
{
Children.Add(element);
}
public int Columns
{
get { return (int)GetValue(ColumnsProperty); }
set { SetValue(ColumnsProperty, value); }
}
public static readonly DependencyProperty ColumnsProperty =
DependencyProperty.Register("Columns", typeof(int), typeof(WaterfallPanel), new PropertyMetadata(3));
public double Spacing
{
get { return (double)GetValue(SpacingProperty); }
set { SetValue(SpacingProperty, value); }
}
public static readonly DependencyProperty SpacingProperty =
DependencyProperty.Register("Spacing", typeof(double), typeof(WaterfallPanel), new PropertyMetadata(5.0));
}
}
2)示例(一)代码WaterfallPanelExample.xaml如下:
<ScrollViewer>
<wd:WaterfallPanel Width="750">
<wd:WaterfallPanel.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10" />
<Setter Property="BorderBrush" Value="LightGray" />
<Setter Property="BorderThickness" Value="1" />
</Style>
<Style TargetType="ImageBrush">
<Setter Property="Stretch" Value="Fill" />
</Style>
<Style TargetType="Textblock">
<Setter Property="Margin" Value="4,10" />
<Setter Property="Foreground" Value="White" />
</Style>
<Style x:Key="BorderContent" TargetType="Border">
<Setter Property="Height" Value="40" />
<Setter Property="CornerRadius" Value="10,10,0,0" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush Opacity=".3" StartPoint="0,.5" EndPoint="0,1">
<GradientStop Offset="0" Color="DimGray" />
<GradientStop Offset="0.9" Color="Gray" />
<GradientStop Offset="1" Color="Transparent" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</wd:WaterfallPanel.Resources>
<Border Height="340">
<Border.Background>
<ImageBrush ImageSource="http://tse2-mm.cn.bing.net/th/id/OIP-C.WVAYTzW5VMZgAErg-y6EgwAAAA" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="WVAYTzW5VMZgAErg" />
</Border>
</Border>
<Border Height="300">
<Border.Background>
<ImageBrush ImageSource="http://tse1-mm.cn.bing.net/th/id/OIP-C.e51iwDiqzatju6Bf50lJ2QHaMW" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="e51iwDiqzatju6Bf50lJ2QHaMW" />
</Border>
</Border>
<Border Height="280">
<Border.Background>
<ImageBrush ImageSource="http://tse1-mm.cn.bing.net/th/id/OIP-C.DB2fWdfqfr8w3sP7wiboHgHaNK" />
</Bordjavascripter.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="dB2fWdfqfr8w3sP7wiboHgHaNK" />
</Border>
</Border>
<Border Height="350">
<Border.Background>
<ImageBrush ImageSource="http://tse4-mm.cn.bing.net/th/id/OIP-C.IzGLt2NgGhakuvbk008FOwHaK9" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="IzGLt2NgGhakuvbk008FOwHaK9" />
</Border>
</Border>
<Border Height="400">
<Border.Background>
<ImageBrush ImageSource="http://pic4.zhimg.com/v2-6233e57a364dcb3b6c5f066f8b30dab4_r.jpg" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="6233e57a364dcb3b6c5f066f8b30dab4_r" />
</Border>
</Border>
<Border Height="240">
<Border.Background>
<ImageBrush ImageSource="http://tse1-mm.cn.bing.net/th/id/OIP-C.ivs2k5Q7Zx7WRZVuSDUJqQHaJ4" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="ivs2k5Q7Zx7WRZVuSDUJqQHaJ4" />
</Border>
</Border>
<Border Height="290">
<Border.Background>
<ImageBrush ImageSource="http://tse3-mm.cn.bing.net/th/id/OIP-C.sTVQljOS9ntgkUyvDXk68AHaKe" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="sTVQljOS9ntgkUyvDXk68AHaKe" />
</Border>
</Border>
<Border Height="207">
<Border.Backgrouandroidnd>
<ImageBrush ImageSource="http://tse2-mm.cn.bing.net/th/id/OIP-C.caVFPs_YGiHH-7vOpQ7GqwHaHY" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="7vOpQ7GqwHaHY" />
</Border>
</Border>
<Border Height="200">
<Border.Background>
<ImageBrush ImageSource="http://tse2-mm.cn.bing.net/th/id/OIP-C.T_Zi1o-AYSCp4c00D_zCVAHaHa" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="AYSCp4c00D_zCVAHaHa" />
</Border>
</Border>
<Border Height="220">
<Border.Background>
<ImageBrush ImageSource="http://tse2-mm.cn.bing.net/th/id/OIP-C.-EGv7Ycl5Zu46_YIGjNuDgHaH4" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="EGv7Ycl5Zu46_YIGjNuDgHaH4" />
</Border>
</Border>
<Border Height="200">
编程客栈 <Border.Background>
<ImageBrush ImageSource="http://tse4-mm.cn.bing.net/th/id/OIP-C.TQ1f0BMQ7Bo7PuRKnCJAMAHaHa" />
</Border.Background>
<Border Style="{StaticResource BorderChttp://www.devze.comontent}">
<TextBlock Text="TQ1f0BMQ7Bo7PuRKnCJAMAHaHa" />
</Border>
</Border>
<Border Height="450">
<B编程客栈order.Background>
<ImageBrush ImageSource="http://img.zcool.cn/community/01493f5d11d9cca801205e4b24e764.jpg" />
</Border.Background>
<Border Style="{StaticResource BorderContent}">
<TextBlock Text="01493f5d11d9cca801205e4b24e764" />
</Border>
</Border>
</wd:WaterfallPanel>
</ScrollViewer>
3)示例(二)后台添加代码WaterfallPanelExample.xaml.cs 如下:
var ran = new Random();
for (int i = 0; i < 1000; i++)
{
var btn = new Button { Content = i.ToString(), Height = (double)ran.Next(100, 1000) };
MyWaterfallPanel.AddChild(btn);
}
效果图

到此这篇关于基于WPF实现瀑布流控件的文章就介绍到这了,更多相关WPF瀑布流控件内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程客栈(www.devze.com)!
加载中,请稍侯......
精彩评论