Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

My First Windows 8 Application – Metro Puzzle

, 7 Apr 2012
My first Windows 8 application, Metro Puzzle.
PuzzleMetro.zip
PuzzleMetro
bin
Debug
Images
PuzzleMetro.build.appxrecipe
resources.pri
Release
Converters
Images
Help
1.png
2.png
3.png
Logo.png
SmallLogo.png
SplashScreen.png
StoreLogo.png
WideLogo.png
Winner.png
obj
Debug
puzzlemetro
TempPE
Package.appxmanifest
Properties
PuzzleMetro_TemporaryKey.pfx
PuzzleMetro_-_Consumer_Preview.zip
Assets
Logo.png
SmallLogo.png
SplashScreen.png
StoreLogo.png
ARM
Debug
Release
AppX
Assets
Logo.png
SmallLogo.png
SplashScreen.png
StoreLogo.png
Common
Images
Help
1.png
2.png
3.png
Logo.png
SmallLogo.png
SplashScreen.png
StoreLogo.png
WideLogo.png
Winner.png
microsoft.system.package.metadata
S-1-5-21-2796664923-3921637894-3850728130-1001.pckgdep
PuzzleMetro.exe
PuzzleMetro.pdb
resources.pri
vs.appxrecipe
Assets
Common
Help
x64
Debug
Release
x86
Debug
Release
Common
1.png
2.png
3.png
Logo.png
SmallLogo.png
SplashScreen.png
StoreLogo.png
WideLogo.png
Winner.png
Common
DesignTimeResolveAssemblyReferencesInput.cache
intermediatexaml
PuzzleMetro.exe
PuzzleMetro.pdb
LanguageQualifiers.txt.intermediate
Package.appxmanifest
PuzzleMetro.csproj.user
PuzzleMetro_TemporaryKey.pfx
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 PuzzleMetro.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="Chidren"/> 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 (this._overflowColumns == null)
            {
                Children.Add(this.RichTextContent);
                this._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 (this._overflowColumns.Count > overflowIndex)
                {
                    overflow = this._overflowColumns[overflowIndex];
                }
                else
                {
                    overflow = (RichTextBlockOverflow)this.ColumnTemplate.LoadContent();
                    this._overflowColumns.Add(overflow);
                    this.Children.Add(overflow);
                    if (overflowIndex == 0)
                    {
                        this.RichTextContent.OverflowContentTarget = overflow;
                    }
                    else
                    {
                        this._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 (this._overflowColumns.Count > overflowIndex)
            {
                if (overflowIndex == 0)
                {
                    this.RichTextContent.OverflowContentTarget = null;
                }
                else
                {
                    this._overflowColumns[overflowIndex - 1].OverflowContentTarget = null;
                }
                while (this._overflowColumns.Count > overflowIndex)
                {
                    this._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);
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)

About the Author

Shai Raiten
Architect Sela
Israel Israel
Shai Raiten is VS ALM MVP, currently working for Sela Group as a ALM senior consultant and trainer specializes in Microsoft technologies especially Team System and .NET technology. He is currently consulting in various enterprises in Israel, planning and analysis Load and performance problems using Team System, building Team System customizations and adjusts ALM processes for enterprises. Shai is known as one of the top Team System experts in Israel. He conducts lectures and workshops for developers\QA and enterprises who want to specialize in Team System.
 
My Blog: http://blogs.microsoft.co.il/blogs/shair/
Follow on   Twitter

| Advertise | Privacy | Mobile
Web04 | 2.8.140718.1 | Last Updated 7 Apr 2012
Article Copyright 2011 by Shai Raiten
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid