/// <summary> /// Content arrangement. /// </summary> /// <param name="arrangeSize">Arrange size</param> protected override Size ArrangeOverride(Size arrangeSize) { if (Owner.FrozenRowCount == 0) { return(base.ArrangeOverride(arrangeSize)); } var rcChild = new Rect(arrangeSize); int frozenRowCount = 0; double nextFrozenRowStart = 0.0; //indicates the start position for next frozen row double nextNonFrozenRowStart = 0.0; //indicates the start position for next non-frozen row double dataGridVerticalScrollStartY = 0.0; //indicates the start position of the vertical scroll bar. // // determine the vertical offset, row panel offset and other coordinates used for arrange of children // if (Owner != null) { double physicalOffset; var originPoint = new Point(0, 0); IScrollInfo scrollInfo = this; { double verticalOffset = scrollInfo.VerticalOffset; physicalOffset = -1.0 * ComputePhysicalFromLogicalOffset(verticalOffset, false); rcChild.X = -1.0 * scrollInfo.HorizontalOffset; } double sbOffset = VerticalScrollBar.TransformToAncestor(ParentPresenter).Transform(originPoint).Y; double rowsPanelOffset = TransformToAncestor(ParentPresenter).Transform(originPoint).Y; //indicates the offset of rows panel from the start of viewport nextFrozenRowStart = 0.0; double viewportStartY = sbOffset - rowsPanelOffset; //indicates the start of viewport with respect to coordinate system of row panel nextNonFrozenRowStart -= physicalOffset - viewportStartY; if (Owner.FrozenRowCount != null) { frozenRowCount = (int)Owner.FrozenRowCount; } //Debug.WriteLine(string.Format( // "verticalOffset: {0}, physicalOffset: {1}, sbOffset: {2}, viewportStartY: {3}, nextNonFrozeRowStart: {4}", // verticalOffset, // physicalOffset, // sbOffset, // viewportStartY, // nextNonFrozenRowStart)); } // // Arrange and Position Children. // var children = GetRealizedChildren; for (int i = 0; i < children.Count; ++i) { // we are looping through the actual containers; the visual children of this panel. var container = (UIElement)children[i]; var childSize = container.DesiredSize; //TODO: need to handle virtualization // container = ParentPresenter.ItemContainerGenerator.ContainerFromIndex(i) as UIElement; // if (container != null) // { // childSize = container.DesiredSize; // } // else // { // //TODO: handle sizing for virtualization // } //} rcChild.Height = childSize.Height; rcChild.Width = Math.Max(arrangeSize.Width, childSize.Width); if (i < frozenRowCount) { rcChild.Y = nextFrozenRowStart; nextFrozenRowStart += childSize.Height; dataGridVerticalScrollStartY += childSize.Height; } else { if (DoubleUtil.LessThan(nextNonFrozenRowStart, nextFrozenRowStart)) { IScrollInfo scrollInfo = this; var verticalOffset = scrollInfo.VerticalOffset; if (DoubleUtil.LessThan(nextNonFrozenRowStart + childSize.Height, nextFrozenRowStart)) { nextNonFrozenRowStart += childSize.Height; } else { double rowChoppedHeight = nextFrozenRowStart - nextNonFrozenRowStart; if (DoubleUtil.AreClose(rowChoppedHeight, 0.0)) { nextNonFrozenRowStart = nextFrozenRowStart + childSize.Height; } else { double clipHeight = childSize.Height - rowChoppedHeight; nextNonFrozenRowStart = nextFrozenRowStart + clipHeight; } } rcChild.Y = nextFrozenRowStart; } else { rcChild.Y = nextNonFrozenRowStart; nextNonFrozenRowStart += childSize.Height; } } container.Arrange(rcChild); } if (Owner != null) { Owner.NonFrozenRowsViewportVerticalOffset = dataGridVerticalScrollStartY; } return(arrangeSize); }