void OnPropertyChanged(DependencyPropertyChangedEventArgs args) { var property = args.Property; if (property == OrientationProperty) { var orientation = (Orientation)args.NewValue; //Note: For FlowLayout Vertical Orientation means we have a Horizontal ScrollOrientation. Horizontal Orientation means we have a Vertical ScrollOrientation. //i.e. the properties are the inverse of each other. ScrollOrientation scrollOrientation = (orientation == Orientation.Horizontal) ? ScrollOrientation.Vertical : ScrollOrientation.Horizontal; ScrollOrientation = scrollOrientation; } else if (property == MinColumnSpacingProperty) { m_minColumnSpacing = (double)args.NewValue; } else if (property == MinRowSpacingProperty) { m_minRowSpacing = (double)args.NewValue; } else if (property == LineAlignmentProperty) { m_lineAlignment = (FlowLayoutLineAlignment)args.NewValue; } InvalidateLayout(); }
public Size Arrange( Size finalSize, VirtualizingLayoutContext context, bool isWrapping, FlowLayoutLineAlignment lineAlignment, string layoutId) { REPEATER_TRACE_INFO("%*s: \tArrangeLayout \n", context.Indent, layoutId); ArrangeVirtualizingLayout(finalSize, lineAlignment, isWrapping, layoutId); return(new Size( Math.Max(finalSize.Width, m_lastExtent.Width), Math.Max(finalSize.Height, m_lastExtent.Height))); }
void ArrangeVirtualizingLayout( Size finalSize, FlowLayoutLineAlignment lineAlignment, bool isWrapping, string layoutId) { // Walk through the realized elements one line at a time and // align them, Then call element.Arrange with the arranged bounds. int realizedElementCount = m_elementManager.GetRealizedElementCount; if (realizedElementCount > 0) { int countInLine = 1; var previousElementBounds = m_elementManager.GetLayoutBoundsForRealizedIndex(0); var currentLineOffset = MajorStart(previousElementBounds); var spaceAtLineStart = MinorStart(previousElementBounds); double spaceAtLineEnd = 0; double currentLineSize = MajorSize(previousElementBounds); for (int i = 1; i < realizedElementCount; i++) { var currentBounds = m_elementManager.GetLayoutBoundsForRealizedIndex(i); if (MajorStart(currentBounds) != currentLineOffset) { spaceAtLineEnd = Minor(finalSize) - MinorStart(previousElementBounds) - MinorSize(previousElementBounds); PerformLineAlignment(i - countInLine, countInLine, (float)spaceAtLineStart, (float)spaceAtLineEnd, (float)currentLineSize, lineAlignment, isWrapping, finalSize, layoutId); spaceAtLineStart = MinorStart(currentBounds); countInLine = 0; currentLineOffset = MajorStart(currentBounds); currentLineSize = 0; } countInLine++; // for current element currentLineSize = Math.Max(currentLineSize, MajorSize(currentBounds)); previousElementBounds = currentBounds; } // Last line - potentially have a property to customize // aligning the last line or not. if (countInLine > 0) { var spaceAtEnd = Minor(finalSize) - MinorStart(previousElementBounds) - MinorSize(previousElementBounds); PerformLineAlignment(realizedElementCount - countInLine, countInLine, (float)spaceAtLineStart, (float)spaceAtEnd, (float)currentLineSize, lineAlignment, isWrapping, finalSize, layoutId); } } }
// Align elements within a line. Note that this does not modify LayoutBounds. So if we get // repeated measures, the LayoutBounds remain the same in each layout. void PerformLineAlignment( int lineStartIndex, int countInLine, float spaceAtLineStart, float spaceAtLineEnd, float lineSize, FlowLayoutLineAlignment lineAlignment, bool isWrapping, Size finalSize, string layoutId) { for (int rangeIndex = lineStartIndex; rangeIndex < lineStartIndex + countInLine; ++rangeIndex) { var bounds = m_elementManager.GetLayoutBoundsForRealizedIndex(rangeIndex); SetMajorSize(ref bounds, lineSize); if (!m_scrollOrientationSameAsFlow) { // Note: Space at start could potentially be negative if (spaceAtLineStart != 0 || spaceAtLineEnd != 0) { float totalSpace = spaceAtLineStart + spaceAtLineEnd; switch (lineAlignment) { case FlowLayoutLineAlignment.Start: { AddMinorStart(ref bounds, -spaceAtLineStart); break; } case FlowLayoutLineAlignment.End: { AddMinorStart(ref bounds, +spaceAtLineEnd); break; } case FlowLayoutLineAlignment.Center: { AddMinorStart(ref bounds, -spaceAtLineStart); AddMinorStart(ref bounds, +totalSpace / 2); break; } case FlowLayoutLineAlignment.SpaceAround: { float interItemSpace = countInLine >= 1 ? totalSpace / (countInLine * 2) : 0; AddMinorStart(ref bounds, -spaceAtLineStart); AddMinorStart(ref bounds, +interItemSpace * ((rangeIndex - lineStartIndex + 1) * 2 - 1)); break; } case FlowLayoutLineAlignment.SpaceBetween: { float interItemSpace = countInLine > 1 ? totalSpace / (countInLine - 1) : 0; AddMinorStart(ref bounds, -spaceAtLineStart); AddMinorStart(ref bounds, +interItemSpace * (rangeIndex - lineStartIndex)); break; } case FlowLayoutLineAlignment.SpaceEvenly: { float interItemSpace = countInLine >= 1 ? totalSpace / (countInLine + 1) : 0; AddMinorStart(ref bounds, -spaceAtLineStart); AddMinorStart(ref bounds, +interItemSpace * (rangeIndex - lineStartIndex + 1)); break; } } } } bounds.X -= m_lastExtent.X; bounds.Y -= m_lastExtent.Y; if (!isWrapping) { SetMinorSize(ref bounds, Math.Max(MinorSize(bounds), Minor(finalSize))); } var element = m_elementManager.GetAt(rangeIndex); REPEATER_TRACE_INFO("%*s: \tArranging element %d at (%.0f,%.0f,%.0f,%.0f). \n", m_context.Indent, layoutId, m_elementManager.GetDataIndexFromRealizedRangeIndex(rangeIndex), bounds.X, bounds.Y, bounds.Width, bounds.Height); element.Arrange(bounds); } }