diff --git a/HandyControl/Controls/Panel/WaterfallPanel.cs b/HandyControl/Controls/Panel/WaterfallPanel.cs
new file mode 100644
index 00000000..2ddb6ffa
--- /dev/null
+++ b/HandyControl/Controls/Panel/WaterfallPanel.cs
@@ -0,0 +1,85 @@
+using System.Linq;
+using System.Windows;
+using System.Windows.Controls;
+using HandyControl.Data;
+
+namespace HandyControl.Controls
+{
+ public class WaterfallPanel : Panel
+ {
+ public static readonly DependencyProperty GroupsProperty = DependencyProperty.Register(
+ "Groups", typeof(int), typeof(WaterfallPanel), new FrameworkPropertyMetadata(ValueBoxes.Int2Box, FrameworkPropertyMetadataOptions.AffectsMeasure), IsGroupsValid);
+
+ public int Groups
+ {
+ get => (int) GetValue(GroupsProperty);
+ set => SetValue(GroupsProperty, value);
+ }
+
+ private static bool IsGroupsValid(object value)
+ {
+ var v = (int)value;
+ return v >= 1;
+ }
+
+ public static readonly DependencyProperty OrientationProperty = DependencyProperty.Register(
+ "Orientation", typeof(Orientation), typeof(WaterfallPanel), new FrameworkPropertyMetadata(
+ Orientation.Horizontal, FrameworkPropertyMetadataOptions.AffectsMeasure));
+
+ public Orientation Orientation
+ {
+ get => (Orientation) GetValue(OrientationProperty);
+ set => SetValue(OrientationProperty, value);
+ }
+
+ protected override Size MeasureOverride(Size constraint)
+ {
+ if (Groups < 1) return constraint;
+ var children = InternalChildren;
+ Size panelSize;
+
+ if (Orientation == Orientation.Horizontal)
+ {
+ var heightArr = new double[Groups].ToList();
+ var itemWidth = constraint.Width / Groups;
+ if (double.IsNaN(itemWidth) || double.IsInfinity(itemWidth)) return constraint;
+
+ for (int i = 0, count = children.Count; i < count; i++)
+ {
+ var child = children[i];
+ if (child == null) continue;
+
+ child.Measure(constraint);
+ var minIndex = heightArr.IndexOf(heightArr.Min());
+ var minY = heightArr[minIndex];
+ child.Arrange(new Rect(new Point(minIndex * itemWidth, minY), new Size(itemWidth, child.DesiredSize.Height)));
+
+ heightArr[minIndex] = minY + child.DesiredSize.Height;
+ }
+ panelSize = new Size(constraint.Width, heightArr.Max());
+ }
+ else
+ {
+ var widthArr = new double[Groups].ToList();
+ var itemHeight = constraint.Height / Groups;
+ if (double.IsNaN(itemHeight) || double.IsInfinity(itemHeight)) return constraint;
+
+ for (int i = 0, count = children.Count; i < count; i++)
+ {
+ var child = children[i];
+ if (child == null) continue;
+
+ child.Measure(constraint);
+ var minIndex = widthArr.IndexOf(widthArr.Min());
+ var minX = widthArr[minIndex];
+ child.Arrange(new Rect(new Point(minX, minIndex * itemHeight), new Size(child.DesiredSize.Width, itemHeight)));
+
+ widthArr[minIndex] = minX + child.DesiredSize.Width;
+ }
+ panelSize = new Size(widthArr.Max(), constraint.Height);
+ }
+
+ return panelSize;
+ }
+ }
+}
\ No newline at end of file
diff --git a/HandyControl/Data/ValueBoxes.cs b/HandyControl/Data/ValueBoxes.cs
index 63599e41..4536ee0d 100644
--- a/HandyControl/Data/ValueBoxes.cs
+++ b/HandyControl/Data/ValueBoxes.cs
@@ -23,6 +23,8 @@
internal static object Int1Box = 1;
+ internal static object Int2Box = 2;
+
internal static object Int5Box = 5;
internal static object BooleanBox(bool value) => value ? TrueBox : FalseBox;
diff --git a/HandyControl/HandyControl.csproj b/HandyControl/HandyControl.csproj
index 4b9efcc6..69ec2637 100644
--- a/HandyControl/HandyControl.csproj
+++ b/HandyControl/HandyControl.csproj
@@ -134,6 +134,7 @@
+
diff --git a/HandyControlDemo/Data/MessageToken.cs b/HandyControlDemo/Data/MessageToken.cs
index 81585c04..51a59bfe 100644
--- a/HandyControlDemo/Data/MessageToken.cs
+++ b/HandyControlDemo/Data/MessageToken.cs
@@ -68,6 +68,8 @@
public static readonly string ShieldDemoCtl = nameof(ShieldDemoCtl);
+ public static readonly string WaterfallPanelDemoCtl = nameof(WaterfallPanelDemoCtl);
+
public static readonly string ButtonDemoCtl = nameof(ButtonDemoCtl);
public static readonly string ToggleButtonDemoCtl = nameof(ToggleButtonDemoCtl);
diff --git a/HandyControlDemo/Data/MessageToken.tt b/HandyControlDemo/Data/MessageToken.tt
index 8d998ceb..5ea16e51 100644
--- a/HandyControlDemo/Data/MessageToken.tt
+++ b/HandyControlDemo/Data/MessageToken.tt
@@ -36,7 +36,8 @@ var controlList = new List
"QQGroupView",
"BlurWindow",
"RateDemoCtl",
- "ShieldDemoCtl"
+ "ShieldDemoCtl",
+ "WaterfallPanelDemoCtl"
};
var styleList = new List
{
diff --git a/HandyControlDemo/HandyControlDemo.csproj b/HandyControlDemo/HandyControlDemo.csproj
index 2d912289..16ec2be7 100644
--- a/HandyControlDemo/HandyControlDemo.csproj
+++ b/HandyControlDemo/HandyControlDemo.csproj
@@ -196,6 +196,9 @@
TimePickerDemoCtl.xaml
+
+ WaterfallPanelDemoCtl.xaml
+
WindowDemoCtl.xaml
@@ -491,6 +494,10 @@
Designer
MSBuild:Compile
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
@@ -671,6 +678,7 @@
TextTemplatingFileGenerator
MessageToken.cs
+
diff --git a/HandyControlDemo/Properties/Langs/Lang.Designer.cs b/HandyControlDemo/Properties/Langs/Lang.Designer.cs
index 37b055b6..643b06b1 100644
--- a/HandyControlDemo/Properties/Langs/Lang.Designer.cs
+++ b/HandyControlDemo/Properties/Langs/Lang.Designer.cs
@@ -47,7 +47,7 @@ namespace HandyControlDemo.Properties.Langs {
}
///
- /// 重写当前线程的 CurrentUICulture 属性
+ /// 使用此强类型资源类,为所有资源查找
/// 重写当前线程的 CurrentUICulture 属性。
///
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
@@ -411,6 +411,15 @@ namespace HandyControlDemo.Properties.Langs {
}
}
+ ///
+ /// 查找类似 组数 的本地化字符串。
+ ///
+ public static string Groups {
+ get {
+ return ResourceManager.GetString("Groups", resourceCulture);
+ }
+ }
+
///
/// 查找类似 信息通知 的本地化字符串。
///
@@ -1050,6 +1059,15 @@ namespace HandyControlDemo.Properties.Langs {
}
}
+ ///
+ /// 查找类似 瀑布流 的本地化字符串。
+ ///
+ public static string WaterfallPanel {
+ get {
+ return ResourceManager.GetString("WaterfallPanel", resourceCulture);
+ }
+ }
+
///
/// 查找类似 窗口 的本地化字符串。
///
diff --git a/HandyControlDemo/Properties/Langs/Lang.en.resx b/HandyControlDemo/Properties/Langs/Lang.en.resx
index 33e53c3e..faf3af75 100644
--- a/HandyControlDemo/Properties/Langs/Lang.en.resx
+++ b/HandyControlDemo/Properties/Langs/Lang.en.resx
@@ -450,4 +450,10 @@
Shield
+
+ WaterfallPanel
+
+
+ Groups
+
\ No newline at end of file
diff --git a/HandyControlDemo/Properties/Langs/Lang.resx b/HandyControlDemo/Properties/Langs/Lang.resx
index f910452f..0bfff05e 100644
--- a/HandyControlDemo/Properties/Langs/Lang.resx
+++ b/HandyControlDemo/Properties/Langs/Lang.resx
@@ -430,4 +430,10 @@
徽章
+
+ 瀑布流
+
+
+ 组数
+
\ No newline at end of file
diff --git a/HandyControlDemo/Resources/Img/LeftMainContent/Panel_16x.png b/HandyControlDemo/Resources/Img/LeftMainContent/Panel_16x.png
new file mode 100644
index 00000000..5c87bed2
Binary files /dev/null and b/HandyControlDemo/Resources/Img/LeftMainContent/Panel_16x.png differ
diff --git a/HandyControlDemo/UserControl/Controls/WaterfallPanelDemoCtl.xaml b/HandyControlDemo/UserControl/Controls/WaterfallPanelDemoCtl.xaml
new file mode 100644
index 00000000..e6a4b020
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/WaterfallPanelDemoCtl.xaml
@@ -0,0 +1,77 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/HandyControlDemo/UserControl/Controls/WaterfallPanelDemoCtl.xaml.cs b/HandyControlDemo/UserControl/Controls/WaterfallPanelDemoCtl.xaml.cs
new file mode 100644
index 00000000..3e9c2468
--- /dev/null
+++ b/HandyControlDemo/UserControl/Controls/WaterfallPanelDemoCtl.xaml.cs
@@ -0,0 +1,10 @@
+namespace HandyControlDemo.UserControl
+{
+ public partial class WaterfallPanelDemoCtl
+ {
+ public WaterfallPanelDemoCtl()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/HandyControlDemo/UserControl/Main/LeftMainContent.xaml b/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
index a208902f..e06f55e4 100644
--- a/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
+++ b/HandyControlDemo/UserControl/Main/LeftMainContent.xaml
@@ -230,6 +230,11 @@
+
+
+
+
+
diff --git a/README.md b/README.md
index 21f676ec..ca049076 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,10 @@
## Latest examples
+### WaterfallPanel
+
+
+
### Rate

diff --git a/Resources/WaterfallPanel.png b/Resources/WaterfallPanel.png
new file mode 100644
index 00000000..3448f06e
Binary files /dev/null and b/Resources/WaterfallPanel.png differ