From 3857ac2d53240cb11e418be3bd19fa1e8dfa8b51 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Fri, 28 Dec 2018 00:14:09 +0800 Subject: [PATCH] add WaterfallPanel --- HandyControl/Controls/Panel/WaterfallPanel.cs | 85 ++++++++++++++++++ HandyControl/Data/ValueBoxes.cs | 2 + HandyControl/HandyControl.csproj | 1 + HandyControlDemo/Data/MessageToken.cs | 2 + HandyControlDemo/Data/MessageToken.tt | 3 +- HandyControlDemo/HandyControlDemo.csproj | 8 ++ .../Properties/Langs/Lang.Designer.cs | 20 ++++- .../Properties/Langs/Lang.en.resx | 6 ++ HandyControlDemo/Properties/Langs/Lang.resx | 6 ++ .../Img/LeftMainContent/Panel_16x.png | Bin 0 -> 139 bytes .../Controls/WaterfallPanelDemoCtl.xaml | 77 ++++++++++++++++ .../Controls/WaterfallPanelDemoCtl.xaml.cs | 10 +++ .../UserControl/Main/LeftMainContent.xaml | 5 ++ README.md | 4 + Resources/WaterfallPanel.png | Bin 0 -> 14244 bytes 15 files changed, 227 insertions(+), 2 deletions(-) create mode 100644 HandyControl/Controls/Panel/WaterfallPanel.cs create mode 100644 HandyControlDemo/Resources/Img/LeftMainContent/Panel_16x.png create mode 100644 HandyControlDemo/UserControl/Controls/WaterfallPanelDemoCtl.xaml create mode 100644 HandyControlDemo/UserControl/Controls/WaterfallPanelDemoCtl.xaml.cs create mode 100644 Resources/WaterfallPanel.png 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 0000000000000000000000000000000000000000..5c87bed249b669f3e9fb4f3d3db1e5954be11e45 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`oCO|{#S9F5he4R}c>anMprEa% zi(^Pd+}p{9Tnq|4%%8XY`LBOfb@ii1N=~_j*$-Zn-3eObDHXV_;feP01(Dy2L@VCU iZ_--P^he*tu}oP0)d>|Z- + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 0000000000000000000000000000000000000000..3448f06e91253fc8b6772785fc125387d088879f GIT binary patch literal 14244 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 literal 0 HcmV?d00001