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 + +![WaterfallPanel](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/WaterfallPanel.png) + ### Rate ![Rate](https://raw.githubusercontent.com/NaBian/HandyControl/master/Resources/Rate.png) 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