private void DrawHorizontalLines(DrawingContext dc) { var yUnit = ActualHeight / count; double x = 0; double y = 0; for (int i = 0; i < count; i++) { y = ActualHeight - i * yUnit; dc.DrawLineSnapped(pen, new Point(0, y), new Point(ActualWidth, y)); } dc.DrawLineSnapped(pen, new Point(0, 0), new Point(ActualWidth, 0)); }
private void DrawVerticalLines(DrawingContext dc) { var xUnit = ActualWidth / count; double x = 0; double y = 0; for (int i = 0; i < count; i++) { x = i * xUnit; dc.DrawLineSnapped(pen, new Point(x, 0), new Point(x, ActualHeight)); } dc.DrawLineSnapped(pen, new Point(ActualWidth, 0), new Point(ActualWidth, ActualHeight)); }
internal void Update(Rect viewport, Size extentSize, bool forceUpdate) { VerifyAccess(); Rect rect = Rect.Intersect(viewport, new Rect(extentSize)); if (!forceUpdate && RenderedViewport.Contains(rect)) { Offset = RenderedViewport.Location - rect.Location; return; } RenderedViewport = viewport; var viewModel = cellsPresenter.ViewModel; if (viewModel == null) { return; } double horizontalOffset = cellsPresenter.HorizontalOffset; var visibleColumns = cellsPresenter.VisibleColumns; int firstVisibleRow = cellsPresenter.FirstVisibleRowIndex; int lastVisibleRow = cellsPresenter.LastVisibleRowIndex; double[] columnEdges = ComputeColumnEdges(visibleColumns); // All columns are visible because we cache the whole row. int firstVisibleColumn = 0; int lastVisibleColumn = visibleColumns.Count - 1; int firstNonFrozenColumn = firstVisibleColumn; int lastNonFrozenColumn = lastVisibleColumn; for (int i = 0; i < visibleColumns.Count; ++i) { if (!visibleColumns[i].IsFrozen) { firstNonFrozenColumn = i; break; } } for (int i = visibleColumns.Count - 1; i >= 0; --i) { if (!visibleColumns[i].IsFrozen) { lastNonFrozenColumn = i; break; } } Offset = new Vector(); RenderedViewport = Rect.Empty; Children.Clear(); using DrawingContext dc = RenderOpen(); int rowCount = viewModel.RowCount; if (rowCount <= 0 || visibleColumns.Count <= 0) { return; } double canvasWidth = cellsPresenter.ActualWidth; double canvasHeight = cellsPresenter.ActualHeight; double verticalOffset = cellsPresenter.VerticalOffset; double rowHeight = cellsPresenter.RowHeight; double columnHeight = Math.Min((rowCount * rowHeight) - verticalOffset, canvasHeight); Brush primaryBackground = cellsPresenter.PrimaryBackground; Brush secondaryBackground = cellsPresenter.SecondaryBackground; for (int row = firstVisibleRow; row <= lastVisibleRow; ++row) { double topEdge = (row * rowHeight) - verticalOffset; var background = row % 2 == 0 ? primaryBackground : secondaryBackground; dc.DrawRectangle( background, null, new Rect(0, topEdge, canvasWidth, rowHeight)); } Brush frozenColumnBackground = cellsPresenter.FrozenColumnBackground; if (firstNonFrozenColumn > firstVisibleColumn) { double leftEdge = columnEdges[firstVisibleColumn]; double rightEdge = columnEdges[firstNonFrozenColumn]; double width = rightEdge - leftEdge; dc.DrawRectangle( frozenColumnBackground, null, new Rect(leftEdge, 0, width, columnHeight)); } if (lastNonFrozenColumn < lastVisibleColumn) { double width = columnEdges[lastVisibleColumn + 1] - columnEdges[lastNonFrozenColumn + 1]; double leftEdge = canvasWidth - width; dc.DrawRectangle( frozenColumnBackground, null, new Rect(leftEdge, 0, width, columnHeight)); } Brush selectionForeground = cellsPresenter.SelectionForeground; Brush selectionBackground = cellsPresenter.SelectionBackground; Pen selectionBorderPen = cellsPresenter.SelectionBorderPen; if (!IsSelectionActive) { selectionForeground = cellsPresenter.InactiveSelectionForeground; selectionBackground = cellsPresenter.InactiveSelectionBackground; selectionBorderPen = cellsPresenter.InactiveSelectionBorderPen; } bool hasVisibleSelection = selectionForeground != null || selectionBackground != null || selectionBorderPen != null; if (hasVisibleSelection) { var rowSelection = viewModel.RowSelection; for (int row = firstVisibleRow; row <= lastVisibleRow; ++row) { if (!rowSelection.Contains(row)) { continue; } double topEdge = (row * rowHeight) - verticalOffset; double bottomEdge = topEdge + rowHeight - 1; dc.DrawRectangle( selectionBackground, null, new Rect( new Point(0, topEdge), new Point(canvasWidth, bottomEdge + 1))); if (!rowSelection.Contains(row - 1)) { dc.DrawLineSnapped( selectionBorderPen, new Point(0, topEdge), new Point(canvasWidth, topEdge)); } if (!rowSelection.Contains(row + 1)) { dc.DrawLineSnapped( selectionBorderPen, new Point(0, bottomEdge), new Point(canvasWidth, bottomEdge)); } } } Pen horizontalGridLinesPen = cellsPresenter.HorizontalGridLinesPen; if (horizontalGridLinesPen != null) { for (int row = firstVisibleRow; row <= lastVisibleRow; ++row) { double bottomEdge = ((row + 1) * rowHeight) - verticalOffset; dc.DrawLineSnapped( horizontalGridLinesPen, new Point(0, bottomEdge), new Point(canvasWidth, bottomEdge)); } } bool hasLeftFrozenColumns = firstNonFrozenColumn > firstVisibleColumn; bool hasRightFrozenColumns = lastNonFrozenColumn < lastVisibleColumn; bool hasFrozenColumns = hasLeftFrozenColumns || hasRightFrozenColumns; if (rowCacheInvalid || (hasFrozenColumns && prevRenderedWidth != canvasWidth) || hasFrozenColumns != prevHasFrozenColumns) { frozenRowCacheInvalid = true; focusVisual = null; nonFrozenAreaClip = null; } prevHasFrozenColumns = hasFrozenColumns; prevRenderedWidth = canvasWidth; PreTrimRowCache(firstVisibleRow, lastVisibleRow); if (visibleColumns.Count > 0) { RenderCells( dc, viewport, canvasWidth, columnHeight, columnEdges, firstVisibleColumn, lastVisibleColumn, firstVisibleRow, lastVisibleRow, firstNonFrozenColumn, lastNonFrozenColumn); } PostTrimRowCache(firstVisibleRow, lastVisibleRow); frozenRowCacheInvalid = false; int focusIndex = viewModel.FocusIndex; Pen focusBorderPen = cellsPresenter.FocusBorderPen; if (IsSelectionActive && focusBorderPen != null && focusIndex >= firstVisibleRow && focusIndex <= lastVisibleRow) { if (focusVisual == null) { double width; if (hasRightFrozenColumns) { width = canvasWidth; if (!hasLeftFrozenColumns) { width += horizontalOffset; } } else { width = columnEdges[columnEdges.Length - 1]; if (hasLeftFrozenColumns) { width -= horizontalOffset; } } var bounds = new Rect(0, 0, width - 1, rowHeight - 1); focusVisual = new DrawingVisual(); focusVisual.Transform = new TranslateTransform(); var context = focusVisual.RenderOpen(); context.DrawRectangleSnapped(null, focusBorderPen, bounds); context.Close(); } double x = hasLeftFrozenColumns ? 0 : -horizontalOffset; double y = (focusIndex * rowHeight) - verticalOffset; AddAtOffset(focusVisual, x, y); } }
private void RenderCells( DrawingContext context, Rect viewport, double canvasWidth, double columnHeight, double[] columnEdges, int firstVisibleColumn, int lastVisibleColumn, int firstVisibleRow, int lastVisibleRow, int firstNonFrozenColumn, int lastNonFrozenColumn) { double horizontalOffset = cellsPresenter.HorizontalOffset; double verticalOffset = cellsPresenter.VerticalOffset; double rowHeight = cellsPresenter.RowHeight; var visibleColumns = cellsPresenter.VisibleColumns; Typeface typeface = cellsPresenter.Typeface; double fontSize = cellsPresenter.FontSize; FlowDirection flowDirection = cellsPresenter.FlowDirection; CultureInfo currentCulture = CultureInfo.CurrentCulture; Pen verticalGridLinesPen = cellsPresenter.VerticalGridLinesPen; Brush keySeparatorBrush = cellsPresenter.KeySeparatorBrush; Brush freezableAreaSeparatorBrush = cellsPresenter.FreezableAreaSeparatorBrush; Brush selectionForeground = cellsPresenter.SelectionForeground; if (!IsSelectionActive) { selectionForeground = cellsPresenter.InactiveSelectionForeground; } var rowSelection = cellsPresenter.ViewModel.RowSelection; double padding = rowHeight / 10; double totalPadding = 2 * padding; for (int col = firstVisibleColumn; col <= lastVisibleColumn; ++col) { double leftEdge = columnEdges[col] - horizontalOffset; double rightEdge = columnEdges[col + 1] - horizontalOffset; double cellWidth = rightEdge - leftEdge; if (verticalGridLinesPen != null) { context.DrawLineSnapped( verticalGridLinesPen, new Point(leftEdge, 0), new Point(leftEdge, columnHeight)); } var column = visibleColumns[col]; if (column.IsKeySeparator) { context.DrawRectangle( keySeparatorBrush, null, new Rect(leftEdge, 0, cellWidth, columnHeight)); } else if (column.IsFreezableAreaSeparator) { context.DrawRectangle( freezableAreaSeparatorBrush, null, new Rect(leftEdge, 0, cellWidth, columnHeight)); } } double lastRightEdge = columnEdges[columnEdges.Length - 1]; if (lastRightEdge <= viewport.Right && verticalGridLinesPen != null) { context.DrawLineSnapped( verticalGridLinesPen, new Point(lastRightEdge, 0), new Point(lastRightEdge, columnHeight)); } bool hasFrozenColumns = firstNonFrozenColumn > firstVisibleColumn || lastNonFrozenColumn < lastVisibleColumn; int viewportSizeHint = lastVisibleRow - firstVisibleRow + 1; for (int row = firstVisibleRow; row <= lastVisibleRow; ++row) { double rowX = -horizontalOffset; double rowY = (row * rowHeight) - verticalOffset; Brush foreground = cellsPresenter.Foreground; if (rowSelection.Contains(row)) { foreground = selectionForeground; } int styleHash = ComputeRowStyleHash(rowHeight, flowDirection, typeface, fontSize, foreground); if (!TryGetCachedRow(row, styleHash, out var rowVisual)) { var rowContext = rowVisual.RenderOpen(); for (int col = firstNonFrozenColumn; col <= lastNonFrozenColumn; ++col) { var column = visibleColumns[col]; if (column.IsKeySeparator || column.IsFreezableAreaSeparator) { continue; } double topEdge = 0; double leftEdge = columnEdges[col]; double rightEdge = columnEdges[col + 1]; double cellWidth = rightEdge - leftEdge; var value = column.GetCellValue(row, viewportSizeHint); if (value != null) { var formatted = new FormattedText( value.ToString(), currentCulture, flowDirection, typeface, fontSize, foreground, null, TextFormattingMode.Display); formatted.MaxTextWidth = Math.Max(cellWidth - totalPadding, 0); formatted.MaxTextHeight = rowHeight; formatted.TextAlignment = column.TextAlignment; formatted.Trimming = TextTrimming.CharacterEllipsis; if (totalPadding < cellWidth) { var offsetY = (rowHeight - formatted.Height) / 2; var origin = new Point( leftEdge + padding, topEdge + offsetY); origin = origin.Round(MidpointRounding.AwayFromZero); rowContext.DrawText(formatted, origin); } } } rowContext.Close(); } AddAtOffset(rowVisual, rowX, rowY); if (hasFrozenColumns) { if (nonFrozenAreaClip == null) { double nonFrozenLeftEdge = columnEdges[firstNonFrozenColumn]; double nonFrozenRightEdge = canvasWidth - (columnEdges[lastVisibleColumn + 1] - columnEdges[lastNonFrozenColumn + 1]); var nonFrozenArea = new Rect( nonFrozenLeftEdge, 0, Math.Max(nonFrozenRightEdge - nonFrozenLeftEdge, 0), rowHeight); nonFrozenAreaClip = new RectangleGeometry(nonFrozenArea) { Transform = new TranslateTransform(horizontalOffset, 0) }; } rowVisual.Clip = nonFrozenAreaClip; ((TranslateTransform)nonFrozenAreaClip.Transform).X = horizontalOffset; if (!TryGetCachedFrozenRow(row, styleHash, out var frozenRowVisual)) { var rowContext = frozenRowVisual.RenderOpen(); for (int col = firstVisibleColumn; col <= lastVisibleColumn; ++col) { var column = visibleColumns[col]; if (column.IsKeySeparator || column.IsFreezableAreaSeparator) { continue; } if (col >= firstNonFrozenColumn && col <= lastNonFrozenColumn) { continue; } double topEdge = 0; double leftEdge = columnEdges[col]; double rightEdge = columnEdges[col + 1]; double cellWidth = rightEdge - leftEdge; if (col > lastNonFrozenColumn) { double distance = columnEdges[lastVisibleColumn + 1] - columnEdges[col]; leftEdge = canvasWidth - distance; rightEdge = leftEdge + cellWidth; } var value = column.GetCellValue(row, viewportSizeHint); if (value != null) { var formatted = new FormattedText( value.ToString(), currentCulture, flowDirection, typeface, fontSize, foreground, null, TextFormattingMode.Display); formatted.MaxTextWidth = Math.Max(cellWidth - totalPadding, 0); formatted.MaxTextHeight = rowHeight; formatted.TextAlignment = column.TextAlignment; formatted.Trimming = TextTrimming.CharacterEllipsis; if (totalPadding < cellWidth) { var offsetY = (rowHeight - formatted.Height) / 2; var origin = new Point( leftEdge + padding, topEdge + offsetY); origin = origin.Round(MidpointRounding.AwayFromZero); rowContext.DrawText(formatted, origin); } } } rowContext.Close(); } AddAtOffset(frozenRowVisual, 0, rowY); } } }