/// <summary>This method performs the actual render operation to show a text label</summary> /// <param name="dc">Drawing context</param> /// <param name="info">Render info</param> /// <param name="scale">The scale.</param> /// <param name="offset">The offset.</param> public virtual void RenderHeader(DrawingContext dc, AutoHeaderTextRenderInfo info, double scale, Point offset) { dc.PushTransform(new TranslateTransform(offset.X, offset.Y)); dc.PushTransform(new ScaleTransform(scale, scale)); dc.PushClip(new RectangleGeometry(info.RenderRect)); info.FormattedText.SetMaxTextWidths(new[] { info.RenderRect.Width }); info.FormattedText.MaxLineCount = 1; info.FormattedText.Trimming = TextTrimming.CharacterEllipsis; dc.DrawText(info.FormattedText, info.RenderRect.TopLeft); dc.Pop(); dc.Pop(); dc.Pop(); }
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 = new Rect(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 = new Rect(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 = new Rect(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 = new Rect(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 = new Rect(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 = new Rect(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 = new Rect(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 = new Rect(groupLeft, 0d, groupWidth, _headers[groupCount].FormattedText.Height +4); InvalidateVisual(); } } top = absoluteTop; left += horizontalGroupSpacing - horizontalSpacing; left += currentMaxColumnWidth; } //return new Size(left + tileWidthDouble, top + tileHeight); return new Size(widthUsed, heightUsed); } catch (Exception ex) { Console.Write(ex.Message); throw; } }
/// <summary> /// When overridden in a derived class, measures the size in layout required for child elements and determines a size for the <see cref="T:System.Windows.FrameworkElement"/>-derived class. /// </summary> /// <param name="availableSize">The available size that this element can give to child elements. Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param> /// <returns> /// The size that this element determines it needs during layout, based on its calculations of child element sizes. /// </returns> protected override Size MeasureOverride(Size availableSize) { if (Children.Count != 2) return base.MeasureOverride(availableSize); // 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(availableSize.Height - top, 0); var width = Math.Max((availableSize.Width - Spacing) / 2, 0); Children[0].Measure(new Size(width, height)); Children[1].Measure(new Size(width, height)); } else { var top = 0d; var height = Math.Max((availableSize.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 = new Rect(0d, 0d, availableSize.Width, text1.FormattedText.Height); top += text1.FormattedText.Height + CaptionSpacing; height1 -= (text1.FormattedText.Height + CaptionSpacing); } Children[0].Measure(new Size(availableSize.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 = new Rect(0d, 0d, availableSize.Width, text2.FormattedText.Height); top += text2.FormattedText.Height + CaptionSpacing; height2 -= (text2.FormattedText.Height + CaptionSpacing); } Children[1].Measure(new Size(availableSize.Width, height2)); } return base.MeasureOverride(availableSize); }