/// <summary> /// Prioritizes elements for layouting. First treat the entrypoints, starting from top-left then around. /// Then select the ones with dependencies that are already laid out. /// </summary> /// <param name="cluster"></param> /// <returns></returns> private IFrameworkElement[] OrderClusterForLayouting(List <Sibling> cluster) { // Give weight to panel alignments. Weight 3 for top or left so that a left-aligned only // element (3) has precedence over a bottom-right aligned element (1+1) var orderedByAlignment = new List <Sibling>(cluster .OrderByDescending(s => (IsAlignLeftWithPanel(s.Element) ? 3 : 0) + (IsAlignTopWithPanel(s.Element) ? 3 : 0) + (RelativePanel.GetAlignRightWithPanel(s.Element) ? 1 : 0) + (RelativePanel.GetAlignBottomWithPanel(s.Element) ? 1 : 0) ) ); var ordered = new List <Sibling>(); while (orderedByAlignment.Count != 0) { // Take the first item in the previous list that has no direct dependency that have not already been selected var next = orderedByAlignment.First(s => s.Dependencies .Where(sd => !sd.IsInferred) .Select(sd => sd.Sibling) .Except(ordered) .Empty() ); orderedByAlignment.Remove(next); ordered.Add(next); } return(ordered .SelectToArray(s => s.Element)); }
/// <summary> /// Returns true if the child is top aligned with Panel or has no vertical alignment instructions /// </summary> private bool IsAlignTopWithPanel(IFrameworkElement child) { return(RelativePanel.GetAlignTopWithPanel(child) || !( RelativePanel.GetAlignBottomWithPanel(child) || RelativePanel.GetAlignVerticalCenterWithPanel(child) || RelativePanel.GetAlignTopWith(child) != null || RelativePanel.GetAlignBottomWith(child) != null || RelativePanel.GetAbove(child) != null || RelativePanel.GetBelow(child) != null )); }
/// <summary> /// Returns true if the child is left aligned with Panel or has no horizontal alignment instructions /// </summary> private bool IsAlignLeftWithPanel(IFrameworkElement child) { return(RelativePanel.GetAlignLeftWithPanel(child) || !( RelativePanel.GetAlignRightWithPanel(child) || RelativePanel.GetAlignHorizontalCenterWithPanel(child) || RelativePanel.GetAlignLeftWith(child) != null || RelativePanel.GetAlignRightWith(child) != null || RelativePanel.GetRightOf(child) != null || RelativePanel.GetLeftOf(child) != null )); }
/// <summary> /// Checks if the given FrameworkElement has any dependencies that would provide a bottom boundary using the existing layout info /// </summary> private double ComputeChildBottomBound( IFrameworkElement child, Size availableSize, Dictionary <IFrameworkElement, SiblingLayoutInfo> siblingLayoutInfos, double childTop, Thickness graphPadding, bool useInferred = false ) { var above = GetAvailableDependencies(GetSibling(child), DependencyType.Above, useInferred, siblingLayoutInfos); if (above.Length != 0) { ExecuteOnSiblingLayoutInfoIfAvailable(child, siblingLayoutInfos, sli => sli.IsBottomBound = !useInferred); return(above.Min(d => siblingLayoutInfos[d.Sibling.Element].Area.Top)); } var bottomAlign = GetAvailableDependencies(GetSibling(child), DependencyType.AlignBottomWith, useInferred, siblingLayoutInfos); if (bottomAlign.Length != 0) { ExecuteOnSiblingLayoutInfoIfAvailable(child, siblingLayoutInfos, sli => sli.IsBottomBound = !useInferred); return(bottomAlign.Min(d => siblingLayoutInfos[d.Sibling.Element].Area.Bottom)); } if (RelativePanel.GetAlignBottomWithPanel(child)) { ExecuteOnSiblingLayoutInfoIfAvailable(child, siblingLayoutInfos, sli => sli.IsBottomBound = true); return(availableSize.Height - graphPadding.Bottom); } if (!useInferred) { ComputeChildBottomBound(child, availableSize, siblingLayoutInfos, childTop, graphPadding, true); } // If there is no dependency, base yourself off of the available height, margins and Height/Min/Max properties var spacing = childTop + child.Margin.Top + child.Margin.Bottom; return(double.IsNaN(child.Height) ? Math.Max( Math.Min( availableSize.Height - graphPadding.Bottom, child.MaxHeight + spacing ), child.MinHeight + spacing ) : child.Height + spacing); }
/// <summary> /// Checks if the given FrameworkElement has any dependencies that would provide a right boundary using the existing layout info /// </summary> private double ComputeChildRightBound( IFrameworkElement child, Size availableSize, Dictionary <IFrameworkElement, SiblingLayoutInfo> siblingLayoutInfos, double childLeft, Thickness graphPadding, bool useInferred = false ) { var leftOf = GetAvailableDependencies(GetSibling(child), DependencyType.LeftOf, useInferred, siblingLayoutInfos); if (leftOf.Length != 0) { ExecuteOnSiblingLayoutInfoIfAvailable(child, siblingLayoutInfos, sli => sli.IsRightBound = !useInferred); return(leftOf.Min(d => siblingLayoutInfos[d.Sibling.Element].Area.Left)); } var rightAlign = GetAvailableDependencies(GetSibling(child), DependencyType.AlignRightWith, useInferred, siblingLayoutInfos); if (rightAlign.Length != 0) { ExecuteOnSiblingLayoutInfoIfAvailable(child, siblingLayoutInfos, sli => sli.IsRightBound = !useInferred); return(rightAlign.Min(d => siblingLayoutInfos[d.Sibling.Element].Area.Right)); } if (RelativePanel.GetAlignRightWithPanel(child)) { ExecuteOnSiblingLayoutInfoIfAvailable(child, siblingLayoutInfos, sli => sli.IsRightBound = true); return(availableSize.Width - graphPadding.Right); } if (!useInferred) { return(ComputeChildRightBound(child, availableSize, siblingLayoutInfos, childLeft, graphPadding, true)); } // If there is no dependency, base yourself off of the available width, margins and Width/Min/Max properties var spacing = childLeft + child.Margin.Left + child.Margin.Right; return(double.IsNaN(child.Width) ? Math.Max( Math.Min( availableSize.Width - graphPadding.Right, child.MaxWidth + spacing ), child.MinWidth + spacing ) : child.Width + spacing); }
/// <summary> /// Makes sure dependencies in the cluster are reversed if they are based on unknown boundaries /// </summary> private void CleanupDependencies(List <Sibling> cluster, bool isHorizontallyInfinite, bool isVerticallyInfinite) { if (!isHorizontallyInfinite && !isVerticallyInfinite) { return; } foreach (var sibling in cluster) { if (isHorizontallyInfinite && RelativePanel.GetAlignRightWithPanel(sibling.Element)) { ReverseDependencies(sibling, true); } if (isVerticallyInfinite && RelativePanel.GetAlignBottomWithPanel(sibling.Element)) { ReverseDependencies(sibling, false); } } }
protected override void OnApplyTemplate() { base.OnApplyTemplate(); //Single click/tap on header relMainPanel = (Windows.UI.Xaml.Controls.RelativePanel)GetTemplateChild("HeaderPanel"); if (relMainPanel != null) { relMainPanel.Tapped += (object sender, TappedRoutedEventArgs e) => { if (!headerToolContentTapped) { IsExpanded = !IsExpanded; setExpandState(IsExpanded); } else { headerToolContentTapped = !headerToolContentTapped; } }; } //Single click/tap on header headerToolContent = (Windows.UI.Xaml.Controls.ContentPresenter)GetTemplateChild("HeaderToolContent"); if (headerToolContent != null) { headerToolContent.Tapped += (object sender, TappedRoutedEventArgs e) => { headerToolContentTapped = true; }; } //Toggle button toggleExpander = (Windows.UI.Xaml.Controls.Primitives.ToggleButton)GetTemplateChild("ExpandCollapseButton"); if (toggleExpander != null) { toggleExpander.Click += (object sender, RoutedEventArgs e) => { IsExpanded = !IsExpanded; setExpandState(IsExpanded); //IsExpanded = !IsExpanded; //toggleExpander.IsChecked = IsExpanded; //changeVisualState(_useTransitions); }; } //Fill with content contentElement = (FrameworkElement)GetTemplateChild("Content"); if (contentElement != null) { _collapsedState = (VisualState)GetTemplateChild("Collapsed"); if ((_collapsedState != null) && (_collapsedState.Storyboard != null)) { _collapsedState.Storyboard.Completed += (object sender, object e) => { contentElement.Visibility = Visibility.Collapsed; }; } } changeVisualState(false); }
/// <summary> /// Gets all the direct dependencies of a FrameworkElement (based on the set AttachedProperties) /// </summary> private Dependency[] GetDependencies(UIElement child, IFrameworkElement[] allChildren) { var dependencies = new List <Dependency>(Dependency.DependencyTypeCount); IFrameworkElement element; element = GetChild(RelativePanel.GetAbove(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.Above)); } element = GetChild(RelativePanel.GetBelow(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.Below)); } element = GetChild(RelativePanel.GetLeftOf(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.LeftOf)); } element = GetChild(RelativePanel.GetRightOf(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.RightOf)); } element = GetChild(RelativePanel.GetAlignBottomWith(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.AlignBottomWith)); } element = GetChild(RelativePanel.GetAlignHorizontalCenterWith(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.AlignHorizontalCenterWith)); } element = GetChild(RelativePanel.GetAlignLeftWith(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.AlignLeftWith)); } element = GetChild(RelativePanel.GetAlignRightWith(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.AlignRightWith)); } element = GetChild(RelativePanel.GetAlignTopWith(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.AlignTopWith)); } element = GetChild(RelativePanel.GetAlignVerticalCenterWith(child), allChildren); if (element != null) { dependencies.Add(new Dependency(element, DependencyType.AlignVerticalCenterWith)); } return(dependencies.ToArray()); }