diff --git a/README.md b/README.md index c2ae3353..62aca62e 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,10 @@ Step 4:enjoy coding ## Latest examples +### RelativePanel + +![RelativePanel](https://raw.githubusercontent.com/HandyOrg/HandyOrgResource/master/HandyControl/Resources/RelativePanel.png) + ### Drawer ![Drawer](https://raw.githubusercontent.com/HandyOrg/HandyOrgResource/master/HandyControl/Resources/Drawer.gif) @@ -107,12 +111,12 @@ Step 4:enjoy coding ![GeometryAnimation](https://raw.githubusercontent.com/HandyOrg/HandyOrgResource/master/HandyControl/Resources/GeometryAnimation.gif) +## History publication + ### SplitButton ![SplitButton](https://raw.githubusercontent.com/HandyOrg/HandyOrgResource/master/HandyControl/Resources/SplitButton.png) -## History publication - ### FloatingBlock ![FloatingBlock](https://raw.githubusercontent.com/HandyOrg/HandyOrgResource/master/HandyControl/Resources/FloatingBlock.gif) diff --git a/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj b/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj index e9ef66a4..bd93971a 100644 --- a/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj +++ b/src/Core_30/HandyControlDemo_Core_30/HandyControlDemo_Core30.csproj @@ -5,12 +5,12 @@ true HandyControlDemo HandyControlDemo - 2.3.0 + 2.4.0 ..\..\Shared\HandyControlDemo_Shared\Resources\Img\icon.ico Debug;Release Copyright © HandyOrg 2018-2019 - 2.3.0.0 - 2.3.0.0 + 2.4.0.0 + 2.4.0.0 8.0 HandyOrg @@ -448,6 +448,9 @@ Resources\Img\LeftMainContent\View_Portrait_16x.png + + Resources\Img\LeftMainContent\TransformRelative_16x.png + diff --git a/src/Core_30/HandyControl_Core_30/HandyControl_Core_30.csproj b/src/Core_30/HandyControl_Core_30/HandyControl_Core_30.csproj index 19e745b0..07314a19 100644 --- a/src/Core_30/HandyControl_Core_30/HandyControl_Core_30.csproj +++ b/src/Core_30/HandyControl_Core_30/HandyControl_Core_30.csproj @@ -4,8 +4,8 @@ true HandyControl HandyControl - 2.3.0 - 2.3.0.0 + 2.4.0 + 2.4.0.0 false false Copyright © HandyOrg 2018-2019 diff --git a/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj b/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj index e5a658ad..65e72972 100644 --- a/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj +++ b/src/Net_40/HandyControlDemo_Net_40/HandyControlDemo_Net_40.csproj @@ -430,6 +430,9 @@ TextTemplatingFileGenerator MessageToken.cs + + Resources\Img\LeftMainContent\TransformRelative_16x.png + Resources\Img\LeftMainContent\View_Portrait_16x.png diff --git a/src/Net_GE45/HandyControlDemo_Net_GE45/HandyControlDemo_Net_GE45.csproj b/src/Net_GE45/HandyControlDemo_Net_GE45/HandyControlDemo_Net_GE45.csproj index 1fa83a40..8a6b97f4 100644 --- a/src/Net_GE45/HandyControlDemo_Net_GE45/HandyControlDemo_Net_GE45.csproj +++ b/src/Net_GE45/HandyControlDemo_Net_GE45/HandyControlDemo_Net_GE45.csproj @@ -496,6 +496,9 @@ TextTemplatingFileGenerator MessageToken.cs + + Resources\Img\LeftMainContent\TransformRelative_16x.png + Resources\Img\LeftMainContent\View_Portrait_16x.png diff --git a/src/Shared/HandyControlDemo_Shared/Data/DemoInfo.json b/src/Shared/HandyControlDemo_Shared/Data/DemoInfo.json index 6c5f4f76..92439c37 100644 --- a/src/Shared/HandyControlDemo_Shared/Data/DemoInfo.json +++ b/src/Shared/HandyControlDemo_Shared/Data/DemoInfo.json @@ -40,7 +40,7 @@ [ "Gravatar", "GravatarDemoCtl", "User_16x", "" ], [ "Badge", "BadgeDemoCtl", "DotLarge_16x", "" ], [ "GotoTop", "GotoTopDemoCtl", "GoToTop_16x", "" ], - [ "SplitButton", "SplitButtonDemoCtl", "SplitButton_16x", "1" ], + [ "SplitButton", "SplitButtonDemoCtl", "SplitButton_16x", "" ], [ "ButtonGroup", "ButtonGroupDemoCtl", "ButtonGroup_16x", "" ], [ "ProgressButton", "ProgressButtonDemoCtl", "ProgressButton_16x", "" ], [ "ChatBubble", "ChatBubbleDemoCtl", "Bubble_16xLG", "" ], @@ -68,6 +68,7 @@ [ "Divider", "DividerDemoCtl", "DottedSplitter_16x", "1" ], [ "CirclePanel", "CirclePanelDemoCtl", "ColorWheel_16x", "" ], [ "Grid", "GridDemoCtl", "GridPane_16x", "" ], + [ "RelativePanel", "RelativePanelDemoCtl", "TransformRelative_16x", "1" ], [ "WaterfallPanel", "WaterfallPanelDemoCtl", "Panel_16x", "" ], [ "HoneycombPanel", "HoneycombPanelDemoCtl", "PolygonHexagon_16x", "" ], [ "TransitioningContentControl", "TransitioningContentControlDemoCtl", "TransitioningContentControl_16x", "" ], diff --git a/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems b/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems index 6d09742c..4fe569a5 100644 --- a/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems +++ b/src/Shared/HandyControlDemo_Shared/HandyControlDemo_Shared.projitems @@ -182,6 +182,9 @@ RateDemoCtl.xaml + + RelativePanelDemoCtl.xaml + RunningBlockDemoCtl.xaml @@ -640,6 +643,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/src/Shared/HandyControlDemo_Shared/Properties/AssemblyInfo.cs b/src/Shared/HandyControlDemo_Shared/Properties/AssemblyInfo.cs index e87a0781..fca449dd 100644 --- a/src/Shared/HandyControlDemo_Shared/Properties/AssemblyInfo.cs +++ b/src/Shared/HandyControlDemo_Shared/Properties/AssemblyInfo.cs @@ -13,5 +13,5 @@ using System.Windows; [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] [assembly: ThemeInfo(ResourceDictionaryLocation.None, ResourceDictionaryLocation.SourceAssembly)] -[assembly: AssemblyVersion("2.3.0")] +[assembly: AssemblyVersion("2.4.0")] #endif \ No newline at end of file diff --git a/src/Shared/HandyControlDemo_Shared/Resources/Img/LeftMainContent/TransformRelative_16x.png b/src/Shared/HandyControlDemo_Shared/Resources/Img/LeftMainContent/TransformRelative_16x.png new file mode 100644 index 00000000..bf04a7a9 Binary files /dev/null and b/src/Shared/HandyControlDemo_Shared/Resources/Img/LeftMainContent/TransformRelative_16x.png differ diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RelativePanelDemoCtl.xaml b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RelativePanelDemoCtl.xaml new file mode 100644 index 00000000..87ca8eca --- /dev/null +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RelativePanelDemoCtl.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RelativePanelDemoCtl.xaml.cs b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RelativePanelDemoCtl.xaml.cs new file mode 100644 index 00000000..747c9b57 --- /dev/null +++ b/src/Shared/HandyControlDemo_Shared/UserControl/Controls/RelativePanelDemoCtl.xaml.cs @@ -0,0 +1,10 @@ +namespace HandyControlDemo.UserControl +{ + public partial class RelativePanelDemoCtl + { + public RelativePanelDemoCtl() + { + InitializeComponent(); + } + } +} diff --git a/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorPicker.cs b/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorPicker.cs index a3106db3..2d1bfd82 100644 --- a/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorPicker.cs +++ b/src/Shared/HandyControl_Shared/Controls/ColorPicker/ColorPicker.cs @@ -434,6 +434,7 @@ namespace HandyControl.Controls /// private void Init() { + if (_panelColor == null) return; UpdateStatus(SelectedBrush.Color); _panelColor.Children.Clear(); foreach (var item in _colorPresetList) diff --git a/src/Shared/HandyControl_Shared/Controls/Growl/Growl.cs b/src/Shared/HandyControl_Shared/Controls/Growl/Growl.cs index 8e285916..c62a0a39 100644 --- a/src/Shared/HandyControl_Shared/Controls/Growl/Growl.cs +++ b/src/Shared/HandyControl_Shared/Controls/Growl/Growl.cs @@ -800,7 +800,7 @@ namespace HandyControl.Controls _timerClose?.Stop(); var transform = new TranslateTransform(); _gridMain.RenderTransform = transform; - var animation = AnimationHelper.CreateAnimation(MaxWidth); + var animation = AnimationHelper.CreateAnimation(ActualWidth); animation.Completed += (s, e) => { if (Parent is Panel panel) diff --git a/src/Shared/HandyControl_Shared/Controls/Growl/GrowlWindow.cs b/src/Shared/HandyControl_Shared/Controls/Growl/GrowlWindow.cs index 38c75cd5..ff968638 100644 --- a/src/Shared/HandyControl_Shared/Controls/Growl/GrowlWindow.cs +++ b/src/Shared/HandyControl_Shared/Controls/Growl/GrowlWindow.cs @@ -3,27 +3,30 @@ using System.Windows.Controls; namespace HandyControl.Controls { - [TemplatePart(Name = ElementGrowPanel, Type = typeof(Panel))] - internal class GrowlWindow : Window + public sealed class GrowlWindow : Window { - private const string ElementGrowPanel = "PART_GrowPanel"; + internal Panel GrowlPanel { get; set; } - public Panel GrowlPanel { get; set; } - - public GrowlWindow() + internal GrowlWindow() { WindowStyle = WindowStyle.None; AllowsTransparency = true; + + GrowlPanel = new StackPanel + { + VerticalAlignment = VerticalAlignment.Top, + Margin = new Thickness(0, 10, 10, 10) + }; + + Content = new ScrollViewer + { + VerticalScrollBarVisibility = ScrollBarVisibility.Hidden, + IsEnableInertia = true, + Content = GrowlPanel + }; } - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - GrowlPanel = GetTemplateChild(ElementGrowPanel) as Panel; - } - - public void Init() + internal void Init() { var desktopWorkingArea = SystemParameters.WorkArea; Height = desktopWorkingArea.Height; diff --git a/src/Shared/HandyControl_Shared/Controls/Other/Badge.cs b/src/Shared/HandyControl_Shared/Controls/Other/Badge.cs index b4a58d2a..b7268aa9 100644 --- a/src/Shared/HandyControl_Shared/Controls/Other/Badge.cs +++ b/src/Shared/HandyControl_Shared/Controls/Other/Badge.cs @@ -78,5 +78,14 @@ namespace HandyControl.Controls get => (Thickness)GetValue(BadgeMarginProperty); set => SetValue(BadgeMarginProperty, value); } + + public static readonly DependencyProperty ShowBadgeProperty = DependencyProperty.Register( + "ShowBadge", typeof(bool), typeof(Badge), new PropertyMetadata(ValueBoxes.TrueBox)); + + public bool ShowBadge + { + get => (bool) GetValue(ShowBadgeProperty); + set => SetValue(ShowBadgeProperty, value); + } } } \ No newline at end of file diff --git a/src/Shared/HandyControl_Shared/Controls/Grid/Col.cs b/src/Shared/HandyControl_Shared/Controls/Panel/Grid/Col.cs similarity index 100% rename from src/Shared/HandyControl_Shared/Controls/Grid/Col.cs rename to src/Shared/HandyControl_Shared/Controls/Panel/Grid/Col.cs diff --git a/src/Shared/HandyControl_Shared/Controls/Grid/Row.cs b/src/Shared/HandyControl_Shared/Controls/Panel/Grid/Row.cs similarity index 100% rename from src/Shared/HandyControl_Shared/Controls/Grid/Row.cs rename to src/Shared/HandyControl_Shared/Controls/Panel/Grid/Row.cs diff --git a/src/Shared/HandyControl_Shared/Controls/Panel/RelativePanel.cs b/src/Shared/HandyControl_Shared/Controls/Panel/RelativePanel.cs new file mode 100644 index 00000000..f2705d0e --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Panel/RelativePanel.cs @@ -0,0 +1,501 @@ +//reference doc : https://docs.microsoft.com/en-us/uwp/api/Windows.UI.Xaml.Controls.RelativePanel + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + public class RelativePanel : Panel + { + private readonly Graph _childGraph; + + public RelativePanel() => _childGraph = new Graph(); + + #region 容器对齐方式 + + public static readonly DependencyProperty AlignLeftWithPanelProperty = DependencyProperty.RegisterAttached( + "AlignLeftWithPanel", typeof(bool), typeof(RelativePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignLeftWithPanel(DependencyObject element, bool value) + => element.SetValue(AlignLeftWithPanelProperty, value); + + public static bool GetAlignLeftWithPanel(DependencyObject element) + => (bool) element.GetValue(AlignLeftWithPanelProperty); + + public static readonly DependencyProperty AlignTopWithPanelProperty = DependencyProperty.RegisterAttached( + "AlignTopWithPanel", typeof(bool), typeof(RelativePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignTopWithPanel(DependencyObject element, bool value) + => element.SetValue(AlignTopWithPanelProperty, value); + + public static bool GetAlignTopWithPanel(DependencyObject element) + => (bool) element.GetValue(AlignTopWithPanelProperty); + + public static readonly DependencyProperty AlignRightWithPanelProperty = DependencyProperty.RegisterAttached( + "AlignRightWithPanel", typeof(bool), typeof(RelativePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignRightWithPanel(DependencyObject element, bool value) + => element.SetValue(AlignRightWithPanelProperty, value); + + public static bool GetAlignRightWithPanel(DependencyObject element) + => (bool) element.GetValue(AlignRightWithPanelProperty); + + public static readonly DependencyProperty AlignBottomWithPanelProperty = DependencyProperty.RegisterAttached( + "AlignBottomWithPanel", typeof(bool), typeof(RelativePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignBottomWithPanel(DependencyObject element, bool value) + => element.SetValue(AlignBottomWithPanelProperty, value); + + public static bool GetAlignBottomWithPanel(DependencyObject element) + => (bool) element.GetValue(AlignBottomWithPanelProperty); + + #endregion + + #region 元素间对齐方式 + + public static readonly DependencyProperty AlignLeftWithProperty = DependencyProperty.RegisterAttached( + "AlignLeftWith", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignLeftWith(DependencyObject element, UIElement value) + => element.SetValue(AlignLeftWithProperty, value); + + public static UIElement GetAlignLeftWith(DependencyObject element) + => (UIElement) element.GetValue(AlignLeftWithProperty); + + public static readonly DependencyProperty AlignTopWithProperty = DependencyProperty.RegisterAttached( + "AlignTopWith", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignTopWith(DependencyObject element, UIElement value) + => element.SetValue(AlignTopWithProperty, value); + + public static UIElement GetAlignTopWith(DependencyObject element) + => (UIElement) element.GetValue(AlignTopWithProperty); + + public static readonly DependencyProperty AlignRightWithProperty = DependencyProperty.RegisterAttached( + "AlignRightWith", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignRightWith(DependencyObject element, UIElement value) + => element.SetValue(AlignRightWithProperty, value); + + public static UIElement GetAlignRightWith(DependencyObject element) + => (UIElement) element.GetValue(AlignRightWithProperty); + + public static readonly DependencyProperty AlignBottomWithProperty = DependencyProperty.RegisterAttached( + "AlignBottomWith", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignBottomWith(DependencyObject element, UIElement value) + => element.SetValue(AlignBottomWithProperty, value); + + public static UIElement GetAlignBottomWith(DependencyObject element) + => (UIElement) element.GetValue(AlignBottomWithProperty); + + #endregion + + #region 元素间位置关系 + + public static readonly DependencyProperty LeftOfProperty = DependencyProperty.RegisterAttached( + "LeftOf", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetLeftOf(DependencyObject element, UIElement value) + => element.SetValue(LeftOfProperty, value); + + public static UIElement GetLeftOf(DependencyObject element) + => (UIElement)element.GetValue(LeftOfProperty); + + public static readonly DependencyProperty AboveProperty = DependencyProperty.RegisterAttached( + "Above", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAbove(DependencyObject element, UIElement value) + => element.SetValue(AboveProperty, value); + + public static UIElement GetAbove(DependencyObject element) + => (UIElement)element.GetValue(AboveProperty); + + public static readonly DependencyProperty RightOfProperty = DependencyProperty.RegisterAttached( + "RightOf", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetRightOf(DependencyObject element, UIElement value) + => element.SetValue(RightOfProperty, value); + + public static UIElement GetRightOf(DependencyObject element) + => (UIElement)element.GetValue(RightOfProperty); + + public static readonly DependencyProperty BelowProperty = DependencyProperty.RegisterAttached( + "Below", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetBelow(DependencyObject element, UIElement value) + => element.SetValue(BelowProperty, value); + + public static UIElement GetBelow(DependencyObject element) + => (UIElement) element.GetValue(BelowProperty); + + #endregion + + #region 居中对齐方式 + + public static readonly DependencyProperty AlignHorizontalCenterWithPanelProperty = DependencyProperty.RegisterAttached( + "AlignHorizontalCenterWithPanel", typeof(bool), typeof(RelativePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignHorizontalCenterWithPanel(DependencyObject element, bool value) + => element.SetValue(AlignHorizontalCenterWithPanelProperty, value); + + public static bool GetAlignHorizontalCenterWithPanel(DependencyObject element) + => (bool)element.GetValue(AlignHorizontalCenterWithPanelProperty); + + public static readonly DependencyProperty AlignVerticalCenterWithPanelProperty = DependencyProperty.RegisterAttached( + "AlignVerticalCenterWithPanel", typeof(bool), typeof(RelativePanel), new FrameworkPropertyMetadata(ValueBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignVerticalCenterWithPanel(DependencyObject element, bool value) + => element.SetValue(AlignVerticalCenterWithPanelProperty, value); + + public static bool GetAlignVerticalCenterWithPanel(DependencyObject element) + => (bool)element.GetValue(AlignVerticalCenterWithPanelProperty); + + public static readonly DependencyProperty AlignHorizontalCenterWithProperty = DependencyProperty.RegisterAttached( + "AlignHorizontalCenterWith", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignHorizontalCenterWith(DependencyObject element, UIElement value) + => element.SetValue(AlignHorizontalCenterWithProperty, value); + + public static UIElement GetAlignHorizontalCenterWith(DependencyObject element) + => (UIElement)element.GetValue(AlignHorizontalCenterWithProperty); + + public static readonly DependencyProperty AlignVerticalCenterWithProperty = DependencyProperty.RegisterAttached( + "AlignVerticalCenterWith", typeof(UIElement), typeof(RelativePanel), new FrameworkPropertyMetadata(default(UIElement), FrameworkPropertyMetadataOptions.AffectsRender)); + + public static void SetAlignVerticalCenterWith(DependencyObject element, UIElement value) + => element.SetValue(AlignVerticalCenterWithProperty, value); + + public static UIElement GetAlignVerticalCenterWith(DependencyObject element) + => (UIElement)element.GetValue(AlignVerticalCenterWithProperty); + + #endregion + + protected override Size MeasureOverride(Size availableSize) + { + foreach (UIElement child in InternalChildren) + { + child?.Measure(availableSize); + } + + return base.MeasureOverride(availableSize); + } + + protected override Size ArrangeOverride(Size arrangeSize) + { + _childGraph.Reset(arrangeSize); + + foreach (UIElement child in InternalChildren) + { + if (child == null) continue; + + var node = _childGraph.AddNode(child); + + node.AlignLeftWithNode = _childGraph.AddLink(node, GetAlignLeftWith(child)); + node.AlignTopWithNode = _childGraph.AddLink(node, GetAlignTopWith(child)); + node.AlignRightWithNode = _childGraph.AddLink(node, GetAlignRightWith(child)); + node.AlignBottomWithNode = _childGraph.AddLink(node, GetAlignBottomWith(child)); + + node.LeftOfNode = _childGraph.AddLink(node, GetLeftOf(child)); + node.AboveNode = _childGraph.AddLink(node, GetAbove(child)); + node.RightOfNode = _childGraph.AddLink(node, GetRightOf(child)); + node.BelowNode = _childGraph.AddLink(node, GetBelow(child)); + + node.AlignHorizontalCenterWith = _childGraph.AddLink(node, GetAlignHorizontalCenterWith(child)); + node.AlignVerticalCenterWith = _childGraph.AddLink(node, GetAlignVerticalCenterWith(child)); + } + + if (_childGraph.CheckCyclic()) + { + throw new Exception("RelativePanel error: Circular dependency detected. Layout could not complete."); + } + + return arrangeSize; + } + + private class GraphNode + { + public Point Position { get; set; } + + public bool Arranged { get; set; } + + public UIElement Element { get; } + + public HashSet OutgoingNodes { get; } + + public GraphNode AlignLeftWithNode { get; set; } + + public GraphNode AlignTopWithNode { get; set; } + + public GraphNode AlignRightWithNode { get; set; } + + public GraphNode AlignBottomWithNode { get; set; } + + public GraphNode LeftOfNode { get; set; } + + public GraphNode AboveNode { get; set; } + + public GraphNode RightOfNode { get; set; } + + public GraphNode BelowNode { get; set; } + + public GraphNode AlignHorizontalCenterWith { get; set; } + + public GraphNode AlignVerticalCenterWith { get; set; } + + public GraphNode(UIElement element) + { + OutgoingNodes = new HashSet(); + Element = element; + } + } + + private class Graph + { + private readonly Dictionary _nodeDic; + + private Size _arrangeSize; + + public Graph() + { + _nodeDic = new Dictionary(); + } + + public GraphNode AddLink(GraphNode from, UIElement to) + { + if (to == null) return null; + + GraphNode nodeTo; + if (_nodeDic.ContainsKey(to)) + { + nodeTo = _nodeDic[to]; + } + else + { + nodeTo = new GraphNode(to); + _nodeDic[to] = nodeTo; + } + + from.OutgoingNodes.Add(nodeTo); + return nodeTo; + } + + public GraphNode AddNode(UIElement value) + { + if (!_nodeDic.ContainsKey(value)) + { + var node = new GraphNode(value); + _nodeDic.Add(value, node); + return node; + } + + return _nodeDic[value]; + } + + public void Reset(Size arrangeSize) + { + _arrangeSize = arrangeSize; + _nodeDic.Clear(); + } + + public bool CheckCyclic() => CheckCyclic(_nodeDic.Values, null); + + private bool CheckCyclic(IEnumerable nodes, HashSet set) + { + if (set == null) + { + set = new HashSet(); + } + + foreach (var node in nodes) + { + /* + * 该节点无任何依赖,所以从这里开始计算元素位置。 + * 因为无任何依赖,所以忽略同级元素 + */ + if (!node.Arranged && node.OutgoingNodes.Count == 0) + { + ArrangeChild(node, true); + continue; + } + + // 判断依赖元素是否全部排列完毕 + if (node.OutgoingNodes.All(item => item.Arranged)) + { + ArrangeChild(node); + continue; + } + + // 判断是否有循环 + if (!set.Add(node.Element)) return true; + + // 没有循环,且有依赖,则继续往下 + return CheckCyclic(node.OutgoingNodes, set); + } + + return false; + } + + private void ArrangeChild(GraphNode node, bool ignoneSibling = false) + { + var child = node.Element; + var childSize = child.DesiredSize; + var childPos = new Point(); + + #region 容器居中对齐 + + if (GetAlignHorizontalCenterWithPanel(child)) + { + childPos.X = (_arrangeSize.Width - childSize.Width) / 2; + } + + if (GetAlignVerticalCenterWithPanel(child)) + { + childPos.Y = (_arrangeSize.Height - childSize.Height) / 2; + } + + #endregion + + var alignLeftWithPanel = GetAlignLeftWithPanel(child); + var alignTopWithPanel = GetAlignTopWithPanel(child); + var alignRightWithPanel = GetAlignRightWithPanel(child); + var alignBottomWithPanel = GetAlignBottomWithPanel(child); + + if (!ignoneSibling) + { + #region 元素间位置 + + if (node.LeftOfNode != null) + { + childPos.X = node.LeftOfNode.Position.X - childSize.Width; + } + + if (node.AboveNode != null) + { + childPos.Y = node.AboveNode.Position.Y - childSize.Height; + } + + if (node.RightOfNode != null) + { + childPos.X = node.RightOfNode.Position.X + node.RightOfNode.Element.DesiredSize.Width; + } + + if (node.BelowNode != null) + { + childPos.Y = node.BelowNode.Position.Y + node.BelowNode.Element.DesiredSize.Height; + } + + #endregion + + #region 元素居中对齐 + + if (node.AlignHorizontalCenterWith != null) + { + childPos.X = node.AlignHorizontalCenterWith.Position.X + + (node.AlignHorizontalCenterWith.Element.DesiredSize.Width - childSize.Width) / 2; + } + + if (node.AlignVerticalCenterWith != null) + { + childPos.Y = node.AlignVerticalCenterWith.Position.Y + + (node.AlignVerticalCenterWith.Element.DesiredSize.Height - childSize.Height) / 2; + } + + #endregion + + #region 元素间对齐 + + if (node.AlignLeftWithNode != null) + { + childPos.X = node.AlignLeftWithNode.Position.X; + } + + if (node.AlignTopWithNode != null) + { + childPos.Y = node.AlignTopWithNode.Position.Y; + } + + if (node.AlignRightWithNode != null) + { + childPos.X = node.AlignRightWithNode.Element.DesiredSize.Width + node.AlignRightWithNode.Position.X - childSize.Width; + } + + if (node.AlignBottomWithNode != null) + { + childPos.Y = node.AlignBottomWithNode.Element.DesiredSize.Height + node.AlignBottomWithNode.Position.Y - childSize.Height; + } + + #endregion + } + + #region 容器对齐 + + if (alignLeftWithPanel) + { + if (node.AlignRightWithNode != null) + { + childPos.X = (node.AlignRightWithNode.Element.DesiredSize.Width + node.AlignRightWithNode.Position.X - childSize.Width) / 2; + } + else + { + childPos.X = 0; + } + } + + if (alignTopWithPanel) + { + if (node.AlignBottomWithNode != null) + { + childPos.Y = (node.AlignBottomWithNode.Element.DesiredSize.Height + node.AlignBottomWithNode.Position.Y - childSize.Height) / 2; + } + else + { + childPos.Y = 0; + } + } + + if (alignRightWithPanel) + { + if (alignLeftWithPanel) + { + childPos.X = (_arrangeSize.Width - childSize.Width) / 2; + } + else if(node.AlignLeftWithNode == null) + { + childPos.X = _arrangeSize.Width - childSize.Width; + } + else + { + childPos.X = (_arrangeSize.Width + node.AlignLeftWithNode.Position.X - childSize.Width) / 2; + } + } + + if (alignBottomWithPanel) + { + if (alignTopWithPanel) + { + childPos.Y = (_arrangeSize.Height - childSize.Height) / 2; + } + else if (node.AlignTopWithNode == null) + { + childPos.Y = _arrangeSize.Height - childSize.Height; + } + else + { + childPos.Y = (_arrangeSize.Height + node.AlignLeftWithNode.Position.Y - childSize.Height) / 2; + } + } + + #endregion + + child.Arrange(new Rect(childPos.X, childPos.Y, childSize.Width, childSize.Height)); + node.Position = childPos; + node.Arranged = true; + } + } + } +} diff --git a/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs index 21a2e572..5433e4a3 100644 --- a/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs +++ b/src/Shared/HandyControl_Shared/Controls/SideMenu/SideMenu.cs @@ -40,6 +40,8 @@ namespace HandyControl.Controls { if (item.Role == SideMenuItemRole.Item) { + _isItemSelected = true; + if (Equals(item, _selectedItem)) return; if (_selectedItem != null) @@ -53,7 +55,6 @@ namespace HandyControl.Controls { Info = e.OriginalSource }); - _isItemSelected = true; } else { @@ -92,7 +93,10 @@ namespace HandyControl.Controls } else if(_selectedHeader != null) { - _selectedHeader.SelectDefaultItem(); + if (AutoSelect) + { + _selectedHeader.SelectDefaultItem(); + } _isItemSelected = false; } } @@ -117,6 +121,15 @@ namespace HandyControl.Controls protected override bool IsItemItsOwnContainerOverride(object item) => item is SideMenuItem; + public static readonly DependencyProperty AutoSelectProperty = DependencyProperty.Register( + "AutoSelect", typeof(bool), typeof(SideMenu), new PropertyMetadata(ValueBoxes.TrueBox)); + + public bool AutoSelect + { + get => (bool) GetValue(AutoSelectProperty); + set => SetValue(AutoSelectProperty, value); + } + public static readonly DependencyProperty ExpandModeProperty = DependencyProperty.Register( "ExpandMode", typeof(ExpandMode), typeof(SideMenu), new PropertyMetadata(default(ExpandMode), OnExpandModeChanged)); diff --git a/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs b/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs index f0430347..becf01e0 100644 --- a/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs +++ b/src/Shared/HandyControl_Shared/Controls/TabControl/TabItem.cs @@ -102,7 +102,15 @@ namespace HandyControl.Controls /// internal TabPanel TabPanel { - get => _tabPanel ??= TabControlParent.HeaderPanel; + get + { + if (_tabPanel == null && TabControlParent != null) + { + _tabPanel = TabControlParent.HeaderPanel; + } + + return _tabPanel; + } set => _tabPanel = value; } diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index 32a40820..b01bf9b2 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -35,6 +35,7 @@ + @@ -90,8 +91,8 @@ - - + + diff --git a/src/Shared/HandyControl_Shared/Properties/AssemblyInfo.cs b/src/Shared/HandyControl_Shared/Properties/AssemblyInfo.cs index 15e58489..65c79a43 100644 --- a/src/Shared/HandyControl_Shared/Properties/AssemblyInfo.cs +++ b/src/Shared/HandyControl_Shared/Properties/AssemblyInfo.cs @@ -12,7 +12,7 @@ using System.Runtime.InteropServices; [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: AssemblyVersion("2.3.0")] +[assembly: AssemblyVersion("2.4.0")] #endif [assembly: XmlnsDefinition("https://handyorg.github.io/handycontrol", "HandyControl.Controls")] diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/BadgeBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/BadgeBaseStyle.xaml index 627fa2b4..9bf504de 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Base/BadgeBaseStyle.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/BadgeBaseStyle.xaml @@ -11,7 +11,7 @@ - + @@ -33,14 +33,14 @@ - + - + @@ -62,7 +62,7 @@ - + diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Growl.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Growl.xaml index f54f7525..0d11a4e3 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Growl.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Growl.xaml @@ -19,15 +19,6 @@ - - - - - - - - -