/// <summary> /// When overridden in a derived class, positions child elements and determines a size for a <see cref="T:System.Windows.FrameworkElement"/> derived class. /// </summary> /// <param name="finalSize">The final area within the parent that this element should use to arrange itself and its children.</param> /// <returns> /// The actual size used. /// </returns> protected override Size ArrangeOverride(Size finalSize) { if (Children.Count != 2) { return(base.ArrangeOverride(finalSize)); // Not much we can do until we have exactly two elements; } // First, we check whether we have any headers _headers.Clear(); var header1 = GetCaption(Children[0]); var header2 = GetCaption(Children[1]); if (Orientation == Orientation.Vertical) { var maxHeaderHeight = 0d; if (!string.IsNullOrEmpty(header1) || !string.IsNullOrEmpty(header2)) { _headers.Add(new AutoHeaderTextRenderInfo { Text = header1, FormattedText = new FormattedText(header1, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(CaptionFontFamily, CaptionFontStyle, CaptionFontWeight, FontStretches.Normal), CaptionFontSize, CaptionForegroundBrush) }); _headers.Add(new AutoHeaderTextRenderInfo { Text = header2, FormattedText = new FormattedText(header2, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(CaptionFontFamily, CaptionFontStyle, CaptionFontWeight, FontStretches.Normal), CaptionFontSize, CaptionForegroundBrush) }); maxHeaderHeight = Math.Max(_headers[0].FormattedText.Height, _headers[1].FormattedText.Height); } var top = maxHeaderHeight + CaptionSpacing; var height = Math.Max(finalSize.Height - top, 0); var width = Math.Max((finalSize.Width - Spacing) / 2, 0); Children[0].Arrange(GeometryHelper.NewRect(0d, top, width, height)); Children[1].Arrange(GeometryHelper.NewRect(width + Spacing, top, width, height)); if (maxHeaderHeight > 0d) { _headers[0].RenderRect = GeometryHelper.NewRect(0d, 0d, width, maxHeaderHeight); _headers[1].RenderRect = GeometryHelper.NewRect(width + Spacing, 0d, width, maxHeaderHeight); } } else { var top = 0d; var height = Math.Max((finalSize.Height - Spacing) / 2, 0); var height1 = height; var height2 = height; if (!string.IsNullOrEmpty(header1)) { var text1 = new AutoHeaderTextRenderInfo { Text = header1, FormattedText = new FormattedText(header1, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(CaptionFontFamily, CaptionFontStyle, CaptionFontWeight, FontStretches.Normal), CaptionFontSize, CaptionForegroundBrush) }; _headers.Add(text1); text1.RenderRect = GeometryHelper.NewRect(0d, 0d, finalSize.Width, text1.FormattedText.Height); top += text1.FormattedText.Height + CaptionSpacing; height1 -= (text1.FormattedText.Height + CaptionSpacing); } Children[0].Arrange(GeometryHelper.NewRect(0d, top, finalSize.Width, height1)); if (!string.IsNullOrEmpty(header2)) { var text2 = new AutoHeaderTextRenderInfo { Text = header2, FormattedText = new FormattedText(header2, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(CaptionFontFamily, CaptionFontStyle, CaptionFontWeight, FontStretches.Normal), CaptionFontSize, CaptionForegroundBrush) }; _headers.Add(text2); text2.RenderRect = GeometryHelper.NewRect(0d, 0d, finalSize.Width, text2.FormattedText.Height); top += text2.FormattedText.Height + CaptionSpacing; height2 -= (text2.FormattedText.Height + CaptionSpacing); } Children[1].Arrange(GeometryHelper.NewRect(0d, top, finalSize.Width, height2)); } return(finalSize); }
private Size IterateChildren(Size availableSize, Action <UIElement, Rect> methodToCall) { try { var absoluteTop = ContentTopLeftPadding.Height; var top = absoluteTop; var left = ContentTopLeftPadding.Width; var heightUsed = top; var widthUsed = left; var horizontalSpacing = GetHorizontalTileSpacing(this); var verticalSpacing = GetVerticalTileSpacing(this); var horizontalGroupSpacing = GetHorizontalGroupSpacing(this); var tileWidthNormal = GetTileWidth(this); var tileHeight = GetTileHeight(this); var tileWidthDouble = tileWidthNormal * 2 + horizontalSpacing; var tileWidthTiny = (tileWidthNormal - horizontalSpacing) / 2; var groups = GetChildrenByGroup(); // We figure out whether we need to leave space for headers if (RenderHeaders) { _headers.Clear(); var titles = new List <string>(); var foundTitle = false; foreach (var groupKey in groups.Keys) { var group = groups[groupKey]; if (group.Count > 0) { var groupTitle = GetGroupTitleForObject(group[0]); titles.Add(groupTitle); if (!string.IsNullOrEmpty(groupTitle)) { foundTitle = true; } } else { titles.Add(string.Empty); } } if (foundTitle) { var maxHeaderHeight = 0d; foreach (var title in titles) { var header = new AutoHeaderTextRenderInfo { Text = title, FormattedText = new FormattedText(title, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(HeaderFontFamily, HeaderFontStyle, HeaderFontWeight, FontStretches.Normal), HeaderFontSize, HeaderForegroundBrush) }; maxHeaderHeight = Math.Max(header.FormattedText.Height, maxHeaderHeight); _headers.Add(header); } if (maxHeaderHeight > 0) { absoluteTop += maxHeaderHeight + HeaderSpacing; top += maxHeaderHeight + HeaderSpacing; heightUsed += maxHeaderHeight + HeaderSpacing; } } } var groupCount = -1; foreach (var group in groups.Values) { groupCount++; var groupWidth = tileWidthDouble; var groupLeft = left; var currentTinyCount = 0; var currentNormalCount = 0; var currentMaxColumnWidth = 0d; foreach (var child in group) { TileWidthModes tileWidth; var contentPresenter = child as ContentPresenter; if (contentPresenter != null && contentPresenter.Content != null && contentPresenter.Content is DependencyObject) { var dependencyContent = (DependencyObject)contentPresenter.Content; tileWidth = GetTileWidthMode(dependencyContent); child.Visibility = MetroTiles.GetTileVisibility(dependencyContent); } else { tileWidth = GetTileWidthMode(child); } if (tileWidth == TileWidthModes.Default) { tileWidth = DefaultTileWidth; } if (child.Visibility != Visibility.Visible) { continue; } switch (tileWidth) { case TileWidthModes.Tiny: if (currentTinyCount == 0 && top > absoluteTop && top + tileHeight > availableSize.Height) // We are beyond the bottom and can do something about it { top = absoluteTop; left += tileWidthDouble + horizontalSpacing; groupWidth += currentMaxColumnWidth + horizontalSpacing; currentMaxColumnWidth = 0d; } var tinyAreaLeft = left; if (currentNormalCount == 1) { tinyAreaLeft += tileWidthNormal + horizontalSpacing; } switch (currentTinyCount) { case 0: var tinyTileRect0 = GeometryHelper.NewRect(tinyAreaLeft, top, tileWidthTiny, tileWidthTiny); methodToCall(child, tinyTileRect0); heightUsed = Math.Max(heightUsed, tinyTileRect0.Bottom); widthUsed = Math.Max(widthUsed, tinyTileRect0.Right); currentMaxColumnWidth = Math.Max(currentMaxColumnWidth, currentNormalCount == 0 ? tileWidthTiny : tileWidthNormal + horizontalSpacing + tileWidthTiny); break; case 1: var tinyTileRect1 = GeometryHelper.NewRect(tinyAreaLeft + horizontalSpacing + tileWidthTiny, top, tileWidthTiny, tileWidthTiny); methodToCall(child, tinyTileRect1); heightUsed = Math.Max(heightUsed, tinyTileRect1.Bottom); widthUsed = Math.Max(widthUsed, tinyTileRect1.Right); currentMaxColumnWidth = Math.Max(currentMaxColumnWidth, currentNormalCount == 0 ? tileWidthTiny + horizontalSpacing + tileWidthTiny : tileWidthNormal + horizontalSpacing + tileWidthNormal); break; case 2: var tinyTileRect2 = GeometryHelper.NewRect(tinyAreaLeft, top + verticalSpacing + tileWidthTiny, tileWidthTiny, tileWidthTiny); methodToCall(child, tinyTileRect2); heightUsed = Math.Max(heightUsed, tinyTileRect2.Bottom); widthUsed = Math.Max(widthUsed, tinyTileRect2.Right); currentMaxColumnWidth = Math.Max(currentMaxColumnWidth, currentNormalCount == 0 ? tileWidthTiny + horizontalSpacing + tileWidthTiny : tileWidthNormal + horizontalSpacing + tileWidthNormal); break; case 3: var tinyTileRect3 = GeometryHelper.NewRect(tinyAreaLeft + horizontalSpacing + tileWidthTiny, top + verticalSpacing + tileWidthTiny, tileWidthTiny, tileWidthTiny); methodToCall(child, tinyTileRect3); heightUsed = Math.Max(heightUsed, tinyTileRect3.Bottom); widthUsed = Math.Max(widthUsed, tinyTileRect3.Right); currentMaxColumnWidth = Math.Max(currentMaxColumnWidth, currentNormalCount == 0 ? tileWidthTiny + horizontalSpacing + tileWidthTiny : tileWidthNormal + horizontalSpacing + tileWidthNormal); break; } currentTinyCount++; if (currentTinyCount > 3) { currentNormalCount++; currentTinyCount = 0; } if (currentNormalCount > 1) { top += tileHeight + verticalSpacing; currentNormalCount = 0; } break; case TileWidthModes.Normal: if (currentNormalCount == 1 && currentTinyCount > 0) { top += tileHeight + verticalSpacing; currentNormalCount = 0; } if (currentNormalCount == 0 && top > absoluteTop && top + tileHeight > availableSize.Height) // We are beyond the bottom and can do something about it { top = absoluteTop; left += tileWidthDouble + horizontalSpacing; groupWidth += currentMaxColumnWidth + horizontalSpacing; currentMaxColumnWidth = 0d; } var normalTileRect = GeometryHelper.NewRect(currentNormalCount == 1 ? left + tileWidthNormal + horizontalSpacing : left, top, tileWidthNormal, tileHeight); currentTinyCount = 0; currentNormalCount++; methodToCall(child, normalTileRect); heightUsed = Math.Max(heightUsed, normalTileRect.Bottom); widthUsed = Math.Max(widthUsed, normalTileRect.Right); currentMaxColumnWidth = Math.Max(currentMaxColumnWidth, currentNormalCount == 1 ? tileWidthNormal : tileWidthDouble); if (currentNormalCount > 1) { top += tileHeight + verticalSpacing; currentNormalCount = 0; } break; case TileWidthModes.Double: if (currentNormalCount > 0) { top += tileHeight + verticalSpacing; } if (currentTinyCount > 0) { top += tileHeight + verticalSpacing; } if (top > absoluteTop && top + tileHeight > availableSize.Height) // We are beyond the bottom and can do something about it { top = absoluteTop; left += tileWidthDouble + horizontalSpacing; groupWidth += currentMaxColumnWidth + horizontalSpacing; } currentNormalCount = 0; currentTinyCount = 0; var dobleTileRect = GeometryHelper.NewRect(left, top, tileWidthDouble, tileHeight); methodToCall(child, dobleTileRect); heightUsed = Math.Max(heightUsed, dobleTileRect.Bottom); widthUsed = Math.Max(widthUsed, dobleTileRect.Right); currentMaxColumnWidth = tileWidthDouble; top += tileHeight + verticalSpacing; break; case TileWidthModes.DoubleSquare: if (currentNormalCount > 0) { top += tileHeight + verticalSpacing; } if (currentTinyCount > 0) { top += tileHeight + verticalSpacing; } if (top > absoluteTop && top + tileWidthDouble > availableSize.Height) // We are beyond the bottom and can do something about it { top = absoluteTop; left += tileWidthDouble + horizontalSpacing; groupWidth += currentMaxColumnWidth + horizontalSpacing; } currentNormalCount = 0; currentTinyCount = 0; var dobleSquareTileRect = GeometryHelper.NewRect(left, top, tileWidthDouble, tileWidthDouble); methodToCall(child, dobleSquareTileRect); heightUsed = Math.Max(heightUsed, dobleSquareTileRect.Bottom); widthUsed = Math.Max(widthUsed, dobleSquareTileRect.Right); currentMaxColumnWidth = tileWidthDouble; top += tileWidthDouble + verticalSpacing; break; } // Possible headers if (RenderHeaders && _headers.Count > groupCount) { _headers[groupCount].RenderRect = GeometryHelper.NewRect(groupLeft, 0d, groupWidth, _headers[groupCount].FormattedText.Height + 4); InvalidateVisual(); } } top = absoluteTop; left += horizontalGroupSpacing - horizontalSpacing; left += currentMaxColumnWidth; } //return GeometryHelper.NewSize(left + tileWidthDouble, top + tileHeight); return(GeometryHelper.NewSize(widthUsed, heightUsed)); } catch (Exception ex) { Console.Write(ex.Message); throw; } }