/// <summary> /// This method draws additional elements into the main display area /// </summary> /// <param name="dc">Drawing context</param> protected override void CustomRender(DrawingContext dc) { var primaryTitle = string.Empty; var secondaryTitle = string.Empty; foreach (UIElement element in Children) { var elementType = SimpleView.GetUIElementType(element); if (elementType == UIElementTypes.Primary) { primaryTitle = SimpleView.GetUIElementTitle(element); break; } } foreach (UIElement element in Children) { var elementType = SimpleView.GetUIElementType(element); if (elementType == UIElementTypes.Secondary) { secondaryTitle = SimpleView.GetUIElementTitle(element); break; } } var primaryTitleFont = PrimaryTitleFont; var primaryTitleFontSize = PrimaryTitleFontSize; var primaryTitleBrush1 = PrimaryTitleHeaderBrush; var primaryTitleBrush2 = PrimaryTitleFooterBrush; var primaryHeaderBackgroundBrush = PrimaryAreaHeaderBackgroundBrush; var secondaryTitleFont = SecondaryTitleFont; var secondaryTitleFontSize = PrimaryTitleFontSize; var secondaryTitleBrush1 = SecondaryTitleHeaderBrush; var secondaryTitleBrush2 = SecondaryTitleFooterBrush; var secondaryHeaderBackgroundBrush = SecondaryAreaHeaderBackgroundBrush; // Calculating the general areas var primaryRect = new Rect(); switch (CalculatedLayout) { case PrimarySecondaryLayout.PrimaryTopSecondaryBottom: primaryRect.Y = 0d; primaryRect.X = 0d; primaryRect.Height = RowDefinitions[0].ActualHeight + RowDefinitions[1].ActualHeight; primaryRect.Width = ActualWidth; break; case PrimarySecondaryLayout.SecondaryTopPrimaryBottom: primaryRect.Y = RowDefinitions[0].ActualHeight; primaryRect.X = 0d; primaryRect.Height = RowDefinitions[1].ActualHeight + RowDefinitions[2].ActualHeight; primaryRect.Width = ActualWidth; break; case PrimarySecondaryLayout.PrimaryLeftSecondaryRight: primaryRect.Y = 0d; primaryRect.X = 0d; primaryRect.Height = ActualHeight; primaryRect.Width = ColumnDefinitions[0].ActualWidth + ColumnDefinitions[1].ActualWidth; break; case PrimarySecondaryLayout.SecondaryLeftPrimaryRight: primaryRect.Y = 0d; primaryRect.X = ColumnDefinitions[0].ActualWidth; primaryRect.Height = ActualHeight; primaryRect.Width = ColumnDefinitions[1].ActualWidth + ColumnDefinitions[2].ActualWidth; break; } var secondaryRect = new Rect(); switch (CalculatedLayout) { case PrimarySecondaryLayout.PrimaryTopSecondaryBottom: secondaryRect.Y = RowDefinitions[0].ActualHeight + RowDefinitions[1].ActualHeight; secondaryRect.X = 0d; secondaryRect.Height = RowDefinitions[2].ActualHeight; secondaryRect.Width = ActualWidth; break; case PrimarySecondaryLayout.SecondaryTopPrimaryBottom: secondaryRect.Y = 0d; secondaryRect.X = 0d; secondaryRect.Height = RowDefinitions[0].ActualHeight; secondaryRect.Width = ActualWidth; break; case PrimarySecondaryLayout.PrimaryLeftSecondaryRight: secondaryRect.Y = 0d; secondaryRect.X = ColumnDefinitions[0].ActualWidth + ColumnDefinitions[1].ActualWidth; secondaryRect.Height = ActualHeight; secondaryRect.Width = ColumnDefinitions[2].ActualWidth; break; case PrimarySecondaryLayout.SecondaryLeftPrimaryRight: secondaryRect.Y = 0d; secondaryRect.X = 0d; secondaryRect.Height = ActualHeight; secondaryRect.Width = ColumnDefinitions[0].ActualWidth; break; } if (!string.IsNullOrEmpty(primaryTitle)) { var primaryFormattedText1 = new FormattedText(primaryTitle, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(primaryTitleFont, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), primaryTitleFontSize, primaryTitleBrush1) { MaxTextWidth = secondaryRect.Width - 4, Trimming = TextTrimming.CharacterEllipsis }; var primaryFormattedText2 = new FormattedText(primaryTitle, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(primaryTitleFont, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), primaryTitleFontSize, primaryTitleBrush2) { MaxTextWidth = secondaryRect.Width - 4, Trimming = TextTrimming.CharacterEllipsis }; var headerRect = new Rect(primaryRect.X + 2, primaryRect.Y + 2, primaryRect.Width - 4, primaryFormattedText1.Height + 4); dc.DrawRectangle(primaryHeaderBackgroundBrush, null, headerRect); dc.DrawText(primaryFormattedText1, new Point(primaryRect.X + 4, primaryRect.Y + 3)); var mainAreaRect = new Rect(primaryRect.X + 2, primaryRect.Y + headerRect.Height + 4, primaryRect.Width - 4, primaryRect.Height - 2 - headerRect.Height - primaryFormattedText2.Height - 4); dc.DrawRectangle(PrimaryAreaBackgroundBrush, null, mainAreaRect); var tabRect = new Rect(primaryRect.X + 2, primaryRect.Y + primaryRect.Height - primaryFormattedText2.Height - 4, Math.Min(primaryRect.Width, primaryFormattedText2.Width + 10), primaryFormattedText2.Height + 4); dc.DrawRectangle(PrimaryAreaBackgroundBrush, null, tabRect); dc.DrawText(primaryFormattedText2, new Point(tabRect.X + 4, tabRect.Y + 2)); } else if (PrimaryAreaBackgroundBrush != null) { dc.DrawRectangle(PrimaryAreaBackgroundBrush, null, primaryRect); } if (!string.IsNullOrEmpty(secondaryTitle)) { var secondaryFormattedText1 = new FormattedText(secondaryTitle, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(secondaryTitleFont, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), secondaryTitleFontSize, secondaryTitleBrush1) { MaxTextWidth = secondaryRect.Width - 4, Trimming = TextTrimming.CharacterEllipsis }; var secondaryFormattedText2 = new FormattedText(secondaryTitle, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, new Typeface(secondaryTitleFont, FontStyles.Normal, FontWeights.Normal, FontStretches.Normal), secondaryTitleFontSize, secondaryTitleBrush2) { MaxTextWidth = secondaryRect.Width - 4, Trimming = TextTrimming.CharacterEllipsis }; var headerRect = new Rect(secondaryRect.X + 2, secondaryRect.Y + 2, secondaryRect.Width - 4, secondaryFormattedText1.Height + 4); dc.DrawRectangle(secondaryHeaderBackgroundBrush, null, headerRect); dc.DrawText(secondaryFormattedText1, new Point(secondaryRect.X + 4, secondaryRect.Y + 3)); var mainAreaRect = new Rect(secondaryRect.X + 2, secondaryRect.Y + headerRect.Height + 4, secondaryRect.Width - 4, secondaryRect.Height - 2 - headerRect.Height - secondaryFormattedText2.Height - 4); dc.DrawRectangle(SecondaryAreaBackgroundBrush, null, mainAreaRect); var tabRect = new Rect(secondaryRect.X + 2, secondaryRect.Y + secondaryRect.Height - secondaryFormattedText2.Height - 4, Math.Min(secondaryRect.Width, secondaryFormattedText2.Width + 10), secondaryFormattedText2.Height + 4); dc.DrawRectangle(SecondaryAreaBackgroundBrush, null, tabRect); dc.DrawText(secondaryFormattedText2, new Point(tabRect.X + 4, tabRect.Y + 2)); } else if (SecondaryAreaBackgroundBrush != null) { dc.DrawRectangle(SecondaryAreaBackgroundBrush, null, secondaryRect); } }
/// <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) { foreach (UIElement element in Children) { if (SimpleView.GetUIElementType(element) == UIElementTypes.Primary) { if (CanCollapseSecondary && IsSecondaryElementCollapsed) { var minimumCollapsedWidth = 0d; var mainAreaLeft = 0d; if (HeaderRenderer != null) { minimumCollapsedWidth = HeaderRenderer.GetMinimumCollapsedAreaWidth(this); if (SecondaryAreaLocation == SecondaryAreaLocation.Left) { mainAreaLeft = minimumCollapsedWidth + (minimumCollapsedWidth > 0d ? ElementSpacing : 0d); } } var primaryArea = new Rect(mainAreaLeft, 0d, finalSize.Width - minimumCollapsedWidth - (minimumCollapsedWidth > 0d ? ElementSpacing : 0d), finalSize.Height); if (HeaderRenderer != null) { primaryArea = HeaderRenderer.GetPrimaryClientArea(primaryArea, this); } _currentPrimaryArea = primaryArea; element.Arrange(primaryArea); } else { var currentX = 0d; if (SecondaryAreaLocation == SecondaryAreaLocation.Left) { currentX = SecondaryElementWidth + ElementSpacing; } var primaryArea = new Rect(currentX, 0d, Math.Max(finalSize.Width - SecondaryElementWidth - ElementSpacing, 0), finalSize.Height); if (HeaderRenderer != null) { primaryArea = HeaderRenderer.GetPrimaryClientArea(primaryArea, this); } _currentPrimaryArea = primaryArea; element.Arrange(primaryArea); } } else { if (CanCollapseSecondary && IsSecondaryElementCollapsed) { _currentSecondaryArea = new Rect(-100000d, -100000d, 0d, finalSize.Height); element.Arrange(_currentSecondaryArea); } else { var secondaryArea = SecondaryAreaLocation == SecondaryAreaLocation.Left ? new Rect(0d, 0d, SecondaryElementWidth, finalSize.Height) : new Rect(finalSize.Width - SecondaryElementWidth, 0d, SecondaryElementWidth, finalSize.Height); if (HeaderRenderer != null) { secondaryArea = HeaderRenderer.GetSecondaryClientArea(secondaryArea, this); } _currentSecondaryArea = secondaryArea; element.Arrange(secondaryArea); } } } return(base.ArrangeOverride(finalSize)); }
/// <summary> /// Measures the children of a <see cref="T:System.Windows.Controls.Grid" /> in anticipation of arranging them during the <see cref="M:System.Windows.Controls.Grid.ArrangeOverride(System.Windows.Size)" /> pass. /// </summary> /// <param name="constraint">Indicates an upper limit size that should not be exceeded.</param> /// <returns><see cref="T:System.Windows.Size" /> that represents the required size to arrange child content.</returns> protected override Size MeasureOverride(Size constraint) { var noMargin = new Thickness(); foreach (var child in Children.OfType <UIElement>().Where(e => e.Visibility != Visibility.Collapsed)) { var element = child as FrameworkElement; if (element == null) { continue; } var mode = SimpleView.GetUIElementType(element); if (mode == UIElementTypes.Primary) { var localMargin = PrimaryUIElementMargin; if (localMargin != noMargin && element.Margin != localMargin) { element.Margin = localMargin; } } else if (mode == UIElementTypes.Secondary) { var localMargin = SecondaryUIElementMargin; if (localMargin != noMargin && element.Margin != localMargin) { element.Margin = localMargin; } } } var size = base.MeasureOverride(constraint); bool mustInvalidate; // Used to potentially trigger a secondary measure pass var secondaryElementVisible = true; // We find the tallest secondary element. If it is taller than the threshold, we switch to horizontal layout var maxHeight = 0d; foreach (var element in Children.OfType <UIElement>().Where(e => e.Visibility != Visibility.Collapsed)) { var type = SimpleView.GetUIElementType(element); if (type == UIElementTypes.Secondary) { if (element.Visibility != Visibility.Visible) { secondaryElementVisible = false; maxHeight = 0; } else { maxHeight = Math.Max(element.DesiredSize.Height, maxHeight); } } } if (maxHeight > SecondaryUIElementAlignmentChangeSize) { // Going to left/right CalculatedLayout = UIElementOrder == PrimarySecondaryOrientation.SecondaryPrimary ? PrimarySecondaryLayout.SecondaryLeftPrimaryRight : PrimarySecondaryLayout.PrimaryLeftSecondaryRight; mustInvalidate = SizeGrid(CalculatedLayout, secondaryElementVisible ? SecondaryUIElementSize : new GridLength(0d)); UIElement primary = null; var secondary = new List <UIElement>(); // We need to assign children to columns foreach (var child in Children) { var element = child as UIElement; if (element == null) { continue; } var type = SimpleView.GetUIElementType(element); if (type == UIElementTypes.Secondary) { secondary.Add(element); } else { primary = element; } } mustInvalidate = AssignElements(CalculatedLayout, primary, secondary, mustInvalidate); } else { // This is a top/bottom layout CalculatedLayout = UIElementOrder == PrimarySecondaryOrientation.SecondaryPrimary ? PrimarySecondaryLayout.SecondaryTopPrimaryBottom : PrimarySecondaryLayout.PrimaryTopSecondaryBottom; mustInvalidate = SizeGrid(CalculatedLayout, secondaryElementVisible ? SecondaryUIElementSize : new GridLength(0d)); UIElement primary = null; var secondary = new List <UIElement>(); // We need to assign children to rows foreach (var element in Children.OfType <UIElement>().Where(e => e.Visibility != Visibility.Collapsed)) { var type = SimpleView.GetUIElementType(element); if (type == UIElementTypes.Secondary) { secondary.Add(element); } else { primary = element; } } mustInvalidate = AssignElements(CalculatedLayout, primary, secondary, mustInvalidate); } if (maxHeight > 0 && mustInvalidate) { // Need to run all this one more time to make sure everything got picked up right MeasureOverride(constraint); InvalidateVisual(); } return(size); }
/// <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 (HeaderRenderer == null) { HeaderRenderer = new StandardPrimarySecondaryHorizontalPanelHeaderRenderer(); } foreach (UIElement element in Children) { if (SimpleView.GetUIElementType(element) == UIElementTypes.Primary) { if (CanCollapseSecondary && IsSecondaryElementCollapsed) { var minimumCollapsedWidth = 0d; var mainAreaLeft = 0d; if (HeaderRenderer != null) { minimumCollapsedWidth = HeaderRenderer.GetMinimumCollapsedAreaWidth(this); if (SecondaryAreaLocation == SecondaryAreaLocation.Left) { mainAreaLeft = minimumCollapsedWidth + (minimumCollapsedWidth > 0d ? ElementSpacing : 0d); } } var primaryArea = new Rect(mainAreaLeft, 0d, availableSize.Width - minimumCollapsedWidth - (minimumCollapsedWidth > 0d ? ElementSpacing : 0d), availableSize.Height); if (HeaderRenderer != null) { primaryArea = HeaderRenderer.GetPrimaryClientArea(primaryArea, this); } element.Measure(primaryArea.Size); } else { var currentX = 0d; if (SecondaryAreaLocation == SecondaryAreaLocation.Left) { currentX = SecondaryElementWidth + ElementSpacing; } var primaryArea = new Rect(currentX, 0d, Math.Max(availableSize.Width - SecondaryElementWidth - ElementSpacing, 0), availableSize.Height); if (HeaderRenderer != null) { primaryArea = HeaderRenderer.GetPrimaryClientArea(primaryArea, this); } element.Measure(primaryArea.Size); } } else { if (CanCollapseSecondary && IsSecondaryElementCollapsed) { element.Measure(new Size(0, availableSize.Height)); } else { var secondaryArea = SecondaryAreaLocation == SecondaryAreaLocation.Left ? new Rect(0d, 0d, SecondaryElementWidth, availableSize.Height) : new Rect(availableSize.Width - SecondaryElementWidth, 0d, SecondaryElementWidth, availableSize.Height); if (HeaderRenderer != null) { secondaryArea = HeaderRenderer.GetSecondaryClientArea(secondaryArea, this); } element.Measure(secondaryArea.Size); } } } return(base.MeasureOverride(availableSize)); }
private void CreateScrollbars() { if (Parent != null && !(Parent is AdornerDecorator) && (Parent is Grid || Parent is SimpleView || Parent is ContentControl)) { // We need to make sure this control is directly within an adorner decorator // so elements in the adorner layer (scroll bars) behave correctly in the Z-Order var decorator = new AdornerDecorator { VerticalAlignment = VerticalAlignment, HorizontalAlignment = HorizontalAlignment, Margin = new Thickness(Margin.Left, Margin.Top, Margin.Right, Margin.Bottom), Width = Width, Height = Height }; Grid.SetColumn(decorator, Grid.GetColumn(this)); Grid.SetRow(decorator, Grid.GetRow(this)); Grid.SetColumnSpan(decorator, Grid.GetColumnSpan(this)); Grid.SetRowSpan(decorator, Grid.GetRowSpan(this)); SimpleView.SetUIElementTitle(decorator, SimpleView.GetUIElementTitle(this)); SimpleView.SetUIElementType(decorator, SimpleView.GetUIElementType(this)); Margin = new Thickness(0d); VerticalAlignment = VerticalAlignment.Stretch; HorizontalAlignment = HorizontalAlignment.Stretch; var parentPanel = Parent as Panel; if (parentPanel != null) { var childItemIndex = -1; var found = false; foreach (var child in parentPanel.Children) { childItemIndex++; if (child == this) { found = true; break; } } if (found) { parentPanel.Children.Remove(this); parentPanel.Children.Insert(childItemIndex, decorator); decorator.Child = this; } } else { var parentContent = Parent as ContentControl; if (parentContent != null) { parentContent.Content = null; parentContent.Content = decorator; decorator.Child = this; } } } if (_scrollbarsCreated) { return; } _adorner = AdornerLayer.GetAdornerLayer(this); if (_adorner == null) { return; } _adorner.Add(new BidirectionalStackPanelScrollAdorner(this, _scrollHorizontal, _scrollVertical) { Visibility = Visibility.Visible }); _scrollHorizontal.ValueChanged += (s, e) => Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(DispatchInvalidateScroll)); _scrollVertical.ValueChanged += (s, e) => Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(DispatchInvalidateScroll)); _scrollbarsCreated = true; }