/WinRT XAML Toolkit - 1.3.6.0 - Source.zip/WinRTXamlToolkit.StylesBrowser/Common/RichTextColumns.cs
C# | 210 lines | 117 code | 15 blank | 78 comment | 17 complexity | e8bd9f86953b674e0249ab2c1f5a9bb8 MD5 | raw file
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Threading.Tasks;
- using Windows.Foundation;
- using Windows.UI.Xaml;
- using Windows.UI.Xaml.Controls;
- using Windows.UI.Xaml.Data;
- using Windows.UI.Xaml.Documents;
- namespace WinRTXamlToolkit.StylesBrowser.Common
- {
- /// <summary>
- /// Wrapper for <see cref="RichTextBlock"/> that creates as many additional overflow
- /// columns as needed to fit the available content.
- /// </summary>
- /// <example>
- /// The following creates a collection of 400-pixel wide columns spaced 50 pixels apart
- /// to contain arbitrary data-bound content:
- /// <code>
- /// <RichTextColumns>
- /// <RichTextColumns.ColumnTemplate>
- /// <DataTemplate>
- /// <RichTextBlockOverflow Width="400" Margin="50,0,0,0"/>
- /// </DataTemplate>
- /// </RichTextColumns.ColumnTemplate>
- ///
- /// <RichTextBlock Width="400">
- /// <Paragraph>
- /// <Run Text="{Binding Content}"/>
- /// </Paragraph>
- /// </RichTextBlock>
- /// </RichTextColumns>
- /// </code>
- /// </example>
- /// <remarks>Typically used in a horizontally scrolling region where an unbounded amount of
- /// space allows for all needed columns to be created. When used in a vertically scrolling
- /// space there will never be any additional columns.</remarks>
- [Windows.UI.Xaml.Markup.ContentProperty(Name = "RichTextContent")]
- public sealed class RichTextColumns : Panel
- {
- /// <summary>
- /// Identifies the <see cref="RichTextContent"/> dependency property.
- /// </summary>
- public static readonly DependencyProperty RichTextContentProperty =
- DependencyProperty.Register("RichTextContent", typeof(RichTextBlock),
- typeof(RichTextColumns), new PropertyMetadata(null, ResetOverflowLayout));
- /// <summary>
- /// Identifies the <see cref="ColumnTemplate"/> dependency property.
- /// </summary>
- public static readonly DependencyProperty ColumnTemplateProperty =
- DependencyProperty.Register("ColumnTemplate", typeof(DataTemplate),
- typeof(RichTextColumns), new PropertyMetadata(null, ResetOverflowLayout));
- /// <summary>
- /// Initializes a new instance of the <see cref="RichTextColumns"/> class.
- /// </summary>
- public RichTextColumns()
- {
- this.HorizontalAlignment = HorizontalAlignment.Left;
- }
- /// <summary>
- /// Gets or sets the initial rich text content to be used as the first column.
- /// </summary>
- public RichTextBlock RichTextContent
- {
- get { return (RichTextBlock)GetValue(RichTextContentProperty); }
- set { SetValue(RichTextContentProperty, value); }
- }
- /// <summary>
- /// Gets or sets the template used to create additional
- /// <see cref="RichTextBlockOverflow"/> instances.
- /// </summary>
- public DataTemplate ColumnTemplate
- {
- get { return (DataTemplate)GetValue(ColumnTemplateProperty); }
- set { SetValue(ColumnTemplateProperty, value); }
- }
- /// <summary>
- /// Invoked when the content or overflow template is changed to recreate the column layout.
- /// </summary>
- /// <param name="d">Instance of <see cref="RichTextColumns"/> where the change
- /// occurred.</param>
- /// <param name="e">Event data describing the specific change.</param>
- private static void ResetOverflowLayout(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- // When dramatic changes occur, rebuild the column layout from scratch
- var target = d as RichTextColumns;
- if (target != null)
- {
- target._overflowColumns = null;
- target.Children.Clear();
- target.InvalidateMeasure();
- }
- }
- /// <summary>
- /// Lists overflow columns already created. Must maintain a 1:1 relationship with
- /// instances in the <see cref="Panel.Children"/> collection following the initial
- /// RichTextBlock child.
- /// </summary>
- private List<RichTextBlockOverflow> _overflowColumns = null;
- /// <summary>
- /// Determines whether additional overflow columns are needed and if existing columns can
- /// be removed.
- /// </summary>
- /// <param name="availableSize">The size of the space available, used to constrain the
- /// number of additional columns that can be created.</param>
- /// <returns>The resulting size of the original content plus any extra columns.</returns>
- protected override Size MeasureOverride(Size availableSize)
- {
- if (this.RichTextContent == null) return new Size(0, 0);
- // Make sure the RichTextBlock is a child, using the lack of
- // a list of additional columns as a sign that this hasn't been
- // done yet
- if (_overflowColumns == null)
- {
- Children.Add(this.RichTextContent);
- _overflowColumns = new List<RichTextBlockOverflow>();
- }
- // Start by measuring the original RichTextBlock content
- this.RichTextContent.Measure(availableSize);
- var maxWidth = this.RichTextContent.DesiredSize.Width;
- var maxHeight = this.RichTextContent.DesiredSize.Height;
- var hasOverflow = this.RichTextContent.HasOverflowContent;
- // Make sure there are enough overflow columns
- int overflowIndex = 0;
- while (hasOverflow && maxWidth < availableSize.Width && this.ColumnTemplate != null)
- {
- // Use existing overflow columns until we run out, then create
- // more from the supplied template
- RichTextBlockOverflow overflow;
- if (_overflowColumns.Count > overflowIndex)
- {
- overflow = _overflowColumns[overflowIndex];
- }
- else
- {
- overflow = (RichTextBlockOverflow)this.ColumnTemplate.LoadContent();
- _overflowColumns.Add(overflow);
- this.Children.Add(overflow);
- if (overflowIndex == 0)
- {
- this.RichTextContent.OverflowContentTarget = overflow;
- }
- else
- {
- _overflowColumns[overflowIndex - 1].OverflowContentTarget = overflow;
- }
- }
- // Measure the new column and prepare to repeat as necessary
- overflow.Measure(new Size(availableSize.Width - maxWidth, availableSize.Height));
- maxWidth += overflow.DesiredSize.Width;
- maxHeight = Math.Max(maxHeight, overflow.DesiredSize.Height);
- hasOverflow = overflow.HasOverflowContent;
- overflowIndex++;
- }
- // Disconnect extra columns from the overflow chain, remove them from our private list
- // of columns, and remove them as children
- if (_overflowColumns.Count > overflowIndex)
- {
- if (overflowIndex == 0)
- {
- this.RichTextContent.OverflowContentTarget = null;
- }
- else
- {
- _overflowColumns[overflowIndex - 1].OverflowContentTarget = null;
- }
- while (_overflowColumns.Count > overflowIndex)
- {
- _overflowColumns.RemoveAt(overflowIndex);
- this.Children.RemoveAt(overflowIndex + 1);
- }
- }
- // Report final determined size
- return new Size(maxWidth, maxHeight);
- }
- /// <summary>
- /// Arranges the original content and all extra columns.
- /// </summary>
- /// <param name="finalSize">Defines the size of the area the children must be arranged
- /// within.</param>
- /// <returns>The size of the area the children actually required.</returns>
- protected override Size ArrangeOverride(Size finalSize)
- {
- double maxWidth = 0;
- double maxHeight = 0;
- foreach (var child in Children)
- {
- child.Arrange(new Rect(maxWidth, 0, child.DesiredSize.Width, finalSize.Height));
- maxWidth += child.DesiredSize.Width;
- maxHeight = Math.Max(maxHeight, child.DesiredSize.Height);
- }
- return new Size(maxWidth, maxHeight);
- }
- }
- }