/// <summary> /// Arranges and sizes the /// <see cref="T:WinRTXamlToolkit.Controls.WrapPanel" /> control and its /// child elements. /// </summary> /// <param name="finalSize"> /// The area within the parent that the /// <see cref="T:WinRTXamlToolkit.Controls.WrapPanel" /> should use /// arrange itself and its children. /// </param> /// <returns> /// The actual size used by the /// <see cref="T:WinRTXamlToolkit.Controls.WrapPanel" />. /// </returns> protected override Size ArrangeOverride(Size finalSize) { // Variables tracking the size of the current line, and the maximum // size available to fill. Note that the line might represent a row // or a column depending on the orientation. Orientation o = Orientation; OrientedSize lineSize = new OrientedSize(o); OrientedSize maximumSize = new OrientedSize(o, finalSize.Width, finalSize.Height); // Determine the constraints for individual items double itemWidth = ItemWidth; double itemHeight = ItemHeight; bool hasFixedWidth = !itemWidth.IsNaN(); bool hasFixedHeight = !itemHeight.IsNaN(); double indirectOffset = 0; double?directDelta = (o == Orientation.Horizontal) ? (hasFixedWidth ? (double?)itemWidth : null) : (hasFixedHeight ? (double?)itemHeight : null); // Measure each of the Children. We will process the elements one // line at a time, just like during measure, but we will wait until // we've completed an entire line of elements before arranging them. // The lineStart and lineEnd variables track the size of the // currently arranged line. UIElementCollection children = Children; int count = children.Count; int lineStart = 0; for (int lineEnd = 0; lineEnd < count; lineEnd++) { UIElement element = children[lineEnd]; // Get the size of the element OrientedSize elementSize = new OrientedSize( o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); // If this element falls of the edge of the line if (NumericExtensions.IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { // Then we just completed a line and we should arrange it ArrangeLine(lineStart, lineEnd, directDelta, indirectOffset, lineSize.Indirect); // Move the current element to a new line indirectOffset += lineSize.Indirect; lineSize = elementSize; // If the current element is larger than the maximum size if (NumericExtensions.IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { // Arrange the element as a single line ArrangeLine(lineEnd, ++lineEnd, directDelta, indirectOffset, elementSize.Indirect); // Move to a new line indirectOffset += lineSize.Indirect; lineSize = new OrientedSize(o); } // Advance the start index to a new line after arranging lineStart = lineEnd; } else { // Otherwise just add the element to the end of the line lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } // Arrange any elements on the last line if (lineStart < count) { ArrangeLine(lineStart, count, directDelta, indirectOffset, lineSize.Indirect); } return(finalSize); }
private bool HandleScrollByPage(bool up) { // NOTE: This implementation assumes that items are laid out // vertically and the Headers of the TreeViewItems appear above // their ItemsPresenter. The same assumptions are made in WPF. ScrollViewer scrollHost = ItemsControlHelper.ScrollHost; if (scrollHost != null) { double viewportHeight = scrollHost.ViewportHeight; double top; double bottom; (SelectedContainer.HeaderElement ?? SelectedContainer).GetTopAndBottom(scrollHost, out top, out bottom); TreeViewItem selected = null; TreeViewItem next = SelectedContainer; ItemsControl parent = SelectedContainer.ParentItemsControl; if (parent != null) { // We need to start at the root TreeViewItem if we're // scrolling up, but can start at the SelectedItem if // scrolling down. if (up) { while (parent != this) { TreeViewItem parentItem = parent as TreeViewItem; if (parentItem == null) { break; } ItemsControl grandparent = parentItem.ParentItemsControl; if (grandparent == null) { break; } next = parentItem; parent = grandparent; } } int index = parent.ItemContainerGenerator.IndexFromContainer(next); int count = parent.Items.Count; while (parent != null && next != null) { if (next.IsEnabled) { double delta; if (next.HandleScrollByPage(up, scrollHost, viewportHeight, top, bottom, out delta)) { // This item or one of its children was focused return(true); } else if (NumericExtensions.IsGreaterThan(delta, viewportHeight)) { // If the item doesn't fit on the page but it's // already selected, we'll select the next item // even though it doesn't completely fit into // the current view if (selected == SelectedContainer || selected == null) { return(up ? SelectedContainer.HandleUpKey() : SelectedContainer.HandleDownKey()); } break; } else { selected = next; } } index += up ? -1 : 1; if (0 <= index && index < count) { next = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; } else if (parent == this) { // We just finished with the last item in the // TreeView next = null; } else { // Move up the parent chain to the next item while (parent != null) { TreeViewItem oldParent = parent as TreeViewItem; parent = oldParent.ParentItemsControl; if (parent != null) { count = parent.Items.Count; index = parent.ItemContainerGenerator.IndexFromContainer(oldParent) + (up ? -1 : 1); if (0 <= index && index < count) { next = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; break; } else if (parent == this) { next = null; parent = null; } } } } } } if (selected != null) { if (up) { if (selected != SelectedContainer) { return(selected.Focus(FocusState.Programmatic)); } } else { selected.FocusInto(); } } } return(false); }
protected override Size MeasureOverride(Size constraint) { // Variables tracking the size of the current line, the total size // measured so far, and the maximum size available to fill. Note // that the line might represent a row or a column depending on the // orientation. Orientation o = Orientation; OrientedSize lineSize = new OrientedSize(o); OrientedSize totalSize = new OrientedSize(o); OrientedSize maximumSize = new OrientedSize(o, constraint.Width, constraint.Height); // Determine the constraints for individual items double itemWidth = ItemWidth; double itemHeight = ItemHeight; bool hasFixedWidth = !double.IsNaN(itemWidth); bool hasFixedHeight = !double.IsNaN(itemHeight); Size itemSize = new Size( hasFixedWidth ? itemWidth : constraint.Width, hasFixedHeight ? itemHeight : constraint.Height); // Measure each of the Children foreach (UIElement element in Children) { // Determine the size of the element element.Measure(itemSize); OrientedSize elementSize = new OrientedSize( o, hasFixedWidth ? itemWidth : element.DesiredSize.Width, hasFixedHeight ? itemHeight : element.DesiredSize.Height); // If this element falls of the edge of the line if (NumericExtensions.IsGreaterThan(lineSize.Direct + elementSize.Direct, maximumSize.Direct)) { // Update the total size with the direct and indirect growth // for the current line totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; // Move the element to a new line lineSize = elementSize; // If the current element is larger than the maximum size, // place it on a line by itself if (NumericExtensions.IsGreaterThan(elementSize.Direct, maximumSize.Direct)) { // Update the total size for the line occupied by this // single element totalSize.Direct = Math.Max(elementSize.Direct, totalSize.Direct); totalSize.Indirect += elementSize.Indirect; // Move to a new line lineSize = new OrientedSize(o); } } else { // Otherwise just add the element to the end of the line lineSize.Direct += elementSize.Direct; lineSize.Indirect = Math.Max(lineSize.Indirect, elementSize.Indirect); } } // Update the total size with the elements on the last line totalSize.Direct = Math.Max(lineSize.Direct, totalSize.Direct); totalSize.Indirect += lineSize.Indirect; // Return the total size required as an un-oriented quantity return(new Size(totalSize.Width, totalSize.Height)); }
/// <summary> /// Handle keys related to scrolling. /// </summary> /// <param name="key">The key to handle.</param> /// <returns>A value indicating whether the key was handled.</returns> private bool HandleScrollKeys(VirtualKey key) { ScrollViewer scrollHost = ItemsControlHelper.ScrollHost; if (scrollHost != null) { // Some keys (e.g. Left/Right) need to be translated in RightToLeft mode VirtualKey invariantKey = InteractionHelper.GetLogicalKey(FlowDirection, key); switch (invariantKey) { case VirtualKey.PageUp: // Move horizontally if we've run out of room vertically if (!NumericExtensions.IsGreaterThan(scrollHost.ExtentHeight, scrollHost.ViewportHeight)) { scrollHost.PageLeft(); } else { scrollHost.PageUp(); } return(true); case VirtualKey.PageDown: // Move horizontally if we've run out of room vertically if (!NumericExtensions.IsGreaterThan(scrollHost.ExtentHeight, scrollHost.ViewportHeight)) { scrollHost.PageRight(); } else { scrollHost.PageDown(); } return(true); case VirtualKey.Home: scrollHost.ScrollToTop(); return(true); case VirtualKey.End: scrollHost.ScrollToBottom(); return(true); case VirtualKey.Left: scrollHost.LineLeft(); return(true); case VirtualKey.Right: scrollHost.LineRight(); return(true); case VirtualKey.Up: scrollHost.LineUp(); return(true); case VirtualKey.Down: scrollHost.LineDown(); return(true); } } return(false); }