/// <summary> /// Draws the content of a <see cref="T:System.Windows.Media.DrawingContext" /> object during the render pass of a <see cref="T:System.Windows.Controls.Panel" /> element. /// </summary> /// <param name="dc">The <see cref="T:System.Windows.Media.DrawingContext" /> object to draw.</param> protected override void OnRender(DrawingContext dc) { base.OnRender(dc); if (!ShowGroupHeaders || GroupHeaderRenderer == null) { return; } var offsetTop = 0d; if (_scrollVertical.Visibility == Visibility.Visible) { offsetTop = _scrollVertical.Value * -1; } var currentTop = offsetTop + Padding.Top; var currentGroupIsExpanded = true; foreach (var control in _lastControls) { var lineHeight = 0d; if (control.Label != null) { lineHeight = control.Label.DesiredSize.Height; } if (control.Edit != null) { lineHeight = Math.Max(lineHeight, control.Edit.DesiredSize.Height); } lineHeight = SnapToPixel(lineHeight); if (control.Label != null && SimpleView.GetGroupBreak(control.Label)) { var groupTitle = SimpleView.GetGroupTitle(control.Label); if (_renderedGroups.ContainsKey(groupTitle)) { currentGroupIsExpanded = _renderedGroups[groupTitle].IsExpanded; var group = _renderedGroups[groupTitle]; var width = ActualWidth - Padding.Left - Padding.Right; if (_scrollVertical.Visibility == Visibility.Visible) { width -= SystemParameters.VerticalScrollBarWidth; } dc.PushTransform(new TranslateTransform(Padding.Left, currentTop)); GroupHeaderRenderer.RenderHeader(dc, currentTop, width, groupTitle, group.IsExpanded); dc.Pop(); group.LastRenderTopPosition = currentTop; currentTop += _renderedGroups[groupTitle].Height; } } if (currentGroupIsExpanded) { currentTop += lineHeight + VerticalElementSpacing; } } }
/// <summary> /// Invoked when an unhandled MouseDown attached event reaches an element in its route that is derived from this class. Implement this method to add class handling for this event. /// </summary> /// <param name="e">The <see cref="T:System.Windows.Input.MouseButtonEventArgs" /> that contains the event data. This event data reports details about the mouse button that was pressed and the handled state.</param> protected override void OnMouseDown(MouseButtonEventArgs e) { if (e.LeftButton == MouseButtonState.Pressed && e.ClickCount == 1) { foreach (var control in _lastControls) { if (control.Label != null && SimpleView.GetGroupBreak(control.Label)) { var groupTitle = SimpleView.GetGroupTitle(control.Label); if (_renderedGroups.ContainsKey(groupTitle)) { var group = _renderedGroups[groupTitle]; var y = group.LastRenderTopPosition; var positionY = e.GetPosition(this).Y; if (positionY >= y && positionY <= y + group.Height) { e.Handled = true; group.IsExpanded = !group.IsExpanded; InvalidateMeasure(); InvalidateArrange(); InvalidateVisual(); return; } } } } } base.OnMouseDown(e); }
/// <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) { var finalSizeInternal = finalSize; if (Padding.Top > 0 || Padding.Bottom > 0 || Padding.Right > 0 || Padding.Left > 0) { var availableHeight = finalSize.Height - Padding.Top - Padding.Bottom; if (availableHeight < 0d) { availableHeight = 0d; } var availableWidth = finalSize.Width - Padding.Left - Padding.Right; if (availableWidth < 0d) { availableWidth = 0d; } finalSizeInternal = GeometryHelper.NewSize(availableWidth, availableHeight); } if (_lastControls == null) { return(base.ArrangeOverride(finalSize)); } var finalWidth = finalSizeInternal.Width; if (_scrollVertical.Visibility == Visibility.Visible) { finalWidth = Math.Max(finalWidth - SystemParameters.VerticalScrollBarWidth, 1); } var offsetTop = 0d; if (_scrollVertical.Visibility == Visibility.Visible) { offsetTop = _scrollVertical.Value * -1; } var currentTop = offsetTop + Padding.Top; if (!ShowGroupHeaders || GroupHeaderRenderer == null) { foreach (var control in _lastControls) { var lineHeight = 0d; if (control.Label != null) { lineHeight = control.Label.DesiredSize.Height; } if (control.Edit != null) { lineHeight = Math.Max(lineHeight, control.Edit.DesiredSize.Height); } lineHeight = SnapToPixel(lineHeight); if (control.Label != null) { if (!control.LabelSpansFullWidth) { control.Label.Arrange(GeometryHelper.NewRect(Padding.Left, currentTop, _labelWidth, lineHeight)); } else { control.Label.Arrange(GeometryHelper.NewRect(Padding.Left, currentTop, SnapToPixel(finalWidth), lineHeight)); } } if (control.Edit != null && !control.LabelSpansFullWidth) { var editLeft = SnapToPixel(_labelWidth + HorizontalElementSpacing + Padding.Left); var editWidth = Math.Max(SnapToPixel(finalWidth - editLeft + Padding.Left), 0); for (var flowControlCounter = control.AdditionalEditControls.Count - 1; flowControlCounter >= 0; flowControlCounter--) { var flowControl = control.AdditionalEditControls[flowControlCounter]; var flowWidth = Math.Min(flowControl.DesiredSize.Width, editWidth); flowControl.Arrange(GeometryHelper.NewRect(editLeft + editWidth - flowWidth, currentTop, flowWidth, lineHeight)); editWidth -= (flowWidth + AdditionalFlowElementSpacing); if (editWidth < 0.1) { editWidth = 0d; } } control.Edit.Arrange(GeometryHelper.NewRect(editLeft, currentTop, editWidth, lineHeight)); } currentTop += lineHeight + VerticalElementSpacing; } } else { var itemIndent = GroupHeaderRenderer.GetHeaderPaddingUsedForRendering("X").Left; var currentGroupIsExpanded = true; foreach (var control in _lastControls) { var lineHeight = 0d; if (control.Label != null) { lineHeight = control.Label.DesiredSize.Height; } if (control.Edit != null) { lineHeight = Math.Max(lineHeight, control.Edit.DesiredSize.Height); } lineHeight = SnapToPixel(lineHeight); if (control.Label != null && SimpleView.GetGroupBreak(control.Label)) { var groupTitle = SimpleView.GetGroupTitle(control.Label); if (_renderedGroups.ContainsKey(groupTitle)) { currentGroupIsExpanded = _renderedGroups[groupTitle].IsExpanded; currentTop += _renderedGroups[groupTitle].Height; } } if (currentGroupIsExpanded) { if (control.Label != null) { control.Label.Visibility = Visibility.Visible; if (!control.LabelSpansFullWidth) { control.Label.Arrange(GeometryHelper.NewRect(Padding.Left + itemIndent, currentTop, _labelWidth, lineHeight)); } else { control.Label.Arrange(GeometryHelper.NewRect(Padding.Left + itemIndent, currentTop, SnapToPixel(finalWidth - itemIndent), lineHeight)); } } if (control.Edit != null) { control.Edit.Visibility = Visibility.Visible; var editLeft = SnapToPixel(_labelWidth + HorizontalElementSpacing + Padding.Left + itemIndent); var editWidth = Math.Max(SnapToPixel(finalWidth - editLeft + Padding.Left), 0); for (var flowControlCounter = control.AdditionalEditControls.Count - 1; flowControlCounter >= 0; flowControlCounter--) { var flowControl = control.AdditionalEditControls[flowControlCounter]; var flowWidth = Math.Min(flowControl.DesiredSize.Width, editWidth); flowControl.Visibility = Visibility.Visible; flowControl.Arrange(GeometryHelper.NewRect(editLeft + editWidth - flowWidth, currentTop, flowWidth, lineHeight)); editWidth -= (flowWidth + AdditionalFlowElementSpacing); if (editWidth < 0.1) { editWidth = 0d; } } control.Edit.Arrange(GeometryHelper.NewRect(editLeft, currentTop, editWidth, lineHeight)); } currentTop += lineHeight + VerticalElementSpacing; } else { if (control.Label != null) { control.Label.Visibility = Visibility.Collapsed; } if (control.Edit != null) { control.Edit.Visibility = Visibility.Collapsed; } foreach (var flowControl in control.AdditionalEditControls) { flowControl.Visibility = Visibility.Collapsed; } } } } return(base.ArrangeOverride(finalSize)); }
/// <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) { var availableSizeInternal = availableSize; if (Padding.Top > 0 || Padding.Bottom > 0 || Padding.Right > 0 || Padding.Left > 0) { var availableHeight = availableSize.Height - Padding.Top - Padding.Bottom; if (availableHeight < 0d) { availableHeight = 0d; } var availableWidth = availableSize.Width - Padding.Left - Padding.Right; if (availableWidth < 0d) { availableWidth = 0d; } availableSizeInternal = GeometryHelper.NewSize(availableWidth, availableHeight); } _lastControls = GetControls(); InvalidateVisual(); var widestLabel = 0d; var totalHeight = 0d; var foundGroupHeader = false; var groupPadding = new Thickness(); if (ShowGroupHeaders && GroupHeaderRenderer != null) { foundGroupHeader = _lastControls.Where(c => c.Label != null).Any(control => !string.IsNullOrEmpty(SimpleView.GetGroupTitle(control.Label))); } if (foundGroupHeader) { groupPadding = GroupHeaderRenderer.GetHeaderPaddingUsedForRendering("X"); availableSizeInternal = GeometryHelper.NewSize(Math.Max(availableSizeInternal.Width - groupPadding.Left, 0), Math.Max(availableSizeInternal.Height, 0)); } foreach (var control in _lastControls.Where(c => c.Label != null)) { control.Label.Measure(availableSizeInternal); if (!control.LabelSpansFullWidth) // For widest-label measurements, we do not consider span labels, since they always use the full width { widestLabel = Math.Max(control.Label.DesiredSize.Width, widestLabel); } } foreach (var control in _lastControls.Where(c => !c.LabelSpansFullWidth && c.Edit != null)) { var currentMaxWidth = SnapToPixel(availableSizeInternal.Width - widestLabel - HorizontalElementSpacing - groupPadding.Left); for (var flowControlCounter = control.AdditionalEditControls.Count - 1; flowControlCounter >= 0; flowControlCounter--) { var flowControl = control.AdditionalEditControls[flowControlCounter]; var availableEditSize = GeometryHelper.NewSize(currentMaxWidth, availableSize.Height); flowControl.Measure(availableEditSize); currentMaxWidth = Math.Max(SnapToPixel(currentMaxWidth - flowControl.DesiredSize.Width), 0); } control.Edit.Measure(GeometryHelper.NewSize(currentMaxWidth, availableSize.Height)); } var currentGroupIsExpanded = true; foreach (var control in _lastControls) { var itemHeight = 0d; if (control.Label != null) { itemHeight = control.Label.DesiredSize.Height; } if (control.Edit != null && !control.LabelSpansFullWidth) { itemHeight = Math.Max(itemHeight, control.Edit.DesiredSize.Height); foreach (var flowControl in control.AdditionalEditControls) { itemHeight = Math.Max(itemHeight, flowControl.DesiredSize.Height); } } itemHeight = SnapToPixel(itemHeight); if (ShowGroupHeaders && control.Label != null && GroupHeaderRenderer != null && SimpleView.GetGroupBreak(control.Label)) { var groupHeader = SimpleView.GetGroupTitle(control.Label) ?? string.Empty; if (!_renderedGroups.ContainsKey(groupHeader)) { _renderedGroups.Add(groupHeader, new PropertySheetGroupHeaderInfo { IsExpanded = true }); } currentGroupIsExpanded = _renderedGroups[groupHeader].IsExpanded; var currentPadding = GroupHeaderRenderer.GetHeaderPaddingUsedForRendering(string.IsNullOrEmpty(groupHeader) ? "X" : groupHeader); _renderedGroups[groupHeader].Height = currentPadding.Top; totalHeight += SnapToPixel(currentPadding.Top); } if (currentGroupIsExpanded) { totalHeight += itemHeight + VerticalElementSpacing; } } _labelWidth = widestLabel; totalHeight += Padding.Top + Padding.Bottom; _lastTotalHeight = totalHeight; HandleScrollBarVisibility(totalHeight, availableSize); if (_scrollVertical.Visibility == Visibility.Visible) { foreach (var control in _lastControls.Where(c => !c.LabelSpansFullWidth && c.Edit != null)) { var currentMaxWidth = SnapToPixel(SnapToPixel(availableSizeInternal.Width - widestLabel - HorizontalElementSpacing - SystemParameters.VerticalScrollBarWidth - 1)); for (var flowControlCounter = control.AdditionalEditControls.Count - 1; flowControlCounter >= 0; flowControlCounter--) { var flowControl = control.AdditionalEditControls[flowControlCounter]; var availableEditSize = GeometryHelper.NewSize(currentMaxWidth, availableSize.Height); flowControl.Measure(availableEditSize); currentMaxWidth = Math.Max(SnapToPixel(currentMaxWidth - flowControl.DesiredSize.Width), 0); } control.Edit.Measure(GeometryHelper.NewSize(currentMaxWidth, availableSize.Height)); } } return(GeometryHelper.NewSize(availableSize.Width, Math.Min(totalHeight, availableSize.Height))); }