view SilverlightGlimpse/SilverFlow.Controls/FloatingWindow/FloatingWindow.cs @ 63:536498832a79

Latest version before changing bindings to Listbox
author Steven Hollidge <stevenhollidge@hotmail.com>
date Sun, 22 Apr 2012 13:33:42 +0100
parents
children
line wrap: on
line source

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using SilverFlow.Controls.Controllers;
using SilverFlow.Controls.Enums;
using SilverFlow.Controls.Extensions;
using SilverFlow.Controls.Helpers;

namespace SilverFlow.Controls
{
    /// <summary>
    /// Provides a window that can be displayed over a parent window not blocking
    /// interaction with the parent window.
    /// </summary>
    [TemplatePart(Name = PART_Chrome, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = PART_TitleContent, Type = typeof(ContentControl))]
    [TemplatePart(Name = PART_CloseButton, Type = typeof(ButtonBase))]
    [TemplatePart(Name = PART_ContentPresenter, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = PART_ContentRoot, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = PART_ContentBorder, Type = typeof(FrameworkElement))]
    [TemplatePart(Name = PART_Root, Type = typeof(FrameworkElement))]
    [TemplateVisualState(Name = VSMSTATE_StateClosed, GroupName = VSMGROUP_Window)]
    [TemplateVisualState(Name = VSMSTATE_StateOpen, GroupName = VSMGROUP_Window)]
    [TemplateVisualState(Name = VSMSTATE_StateMinimized, GroupName = VSMGROUP_Window)]
    [TemplateVisualState(Name = VSMSTATE_StateRestored, GroupName = VSMGROUP_Window)]
    [TemplateVisualState(Name = VSMSTATE_StateNormal, GroupName = VSMGROUP_Button)]
    [StyleTypedProperty(Property = PROPERTY_TitleStyle, StyleTargetType = typeof(ContentControl))]
    [StyleTypedProperty(Property = PROPERTY_CloseButtonStyle, StyleTargetType = typeof(Button))]
    [StyleTypedProperty(Property = PROPERTY_MinimizeButtonStyle, StyleTargetType = typeof(Button))]
    [StyleTypedProperty(Property = PROPERTY_MaximizeButtonStyle, StyleTargetType = typeof(Button))]
    [StyleTypedProperty(Property = PROPERTY_RestoreButtonStyle, StyleTargetType = typeof(Button))]
    public class FloatingWindow : ContentControl, IResizableElement, IDisposable
    {
        #region Constants

        // Template parts
        private const string PART_Chrome = "Chrome";
        private const string PART_TitleContent = "TitleContent";
        private const string PART_CloseButton = "CloseButton";
        private const string PART_MaximizeButton = "MaximizeButton";
        private const string PART_RestoreButton = "RestoreButton";
        private const string PART_MinimizeButton = "MinimizeButton";
        private const string PART_ContentPresenter = "ContentPresenter";
        private const string PART_ContentRoot = "ContentRoot";
        private const string PART_ContentBorder = "ContentBorder";
        private const string PART_Root = "Root";

        // VSM groups
        private const string VSMGROUP_Window = "WindowStates";
        private const string VSMGROUP_Button = "CommonStates";

        // VSM states
        private const string VSMSTATE_StateNormal = "Normal";
        private const string VSMSTATE_StateClosed = "Closed";
        private const string VSMSTATE_StateOpen = "Open";
        private const string VSMSTATE_StateMinimized = "Minimized";
        private const string VSMSTATE_StateRestored = "Restored";

        // Style typed properties
        private const string PROPERTY_TitleStyle = "TitleStyle";
        private const string PROPERTY_CloseButtonStyle = "CloseButtonStyle";
        private const string PROPERTY_MinimizeButtonStyle = "MinimizeButtonStyle";
        private const string PROPERTY_MaximizeButtonStyle = "MaximizeButtonStyle";
        private const string PROPERTY_RestoreButtonStyle = "RestoreButtonStyle";

        // Thickness of resizing area
        private const double ResizingAreaDefaultValue = 6;

        // Animation duration in milliseconds
        private const double MaximizingDurationInMilliseconds = 20;
        private const double MinimizingDurationInMilliseconds = 200;
        private const double RestoringDurationInMilliseconds = 20;

        #endregion

        #region public bool ShowCloseButton

        /// <summary>
        /// Gets or sets a value indicating whether to show Close button.
        /// </summary>
        /// <value><c>true</c> if to show Close button; otherwise, <c>false</c>.</value>
        public bool ShowCloseButton
        {
            get { return (bool)GetValue(ShowCloseButtonProperty); }
            set { SetValue(ShowCloseButtonProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.ShowCloseButton" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.ShowCloseButton" /> dependency property.
        /// </value>
        public static readonly DependencyProperty ShowCloseButtonProperty =
            DependencyProperty.Register(
            "ShowCloseButton",
            typeof(bool),
            typeof(FloatingWindow),
            new PropertyMetadata(true, OnShowCloseButtonPropertyChanged));

        /// <summary>
        /// ShowCloseButtonProperty PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose ShowCloseButton property is changed.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
        private static void OnShowCloseButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FloatingWindow window = (FloatingWindow)d;

            if (window.closeButton != null)
                window.closeButton.SetVisible((bool)e.NewValue);
        }

        #endregion

        #region public bool ShowMaximizeButton

        /// <summary>
        /// Gets or sets a value indicating whether to show Maximize button.
        /// </summary>
        /// <value><c>true</c> if to show Maximize button; otherwise, <c>false</c>.</value>
        public bool ShowMaximizeButton
        {
            get { return (bool)GetValue(ShowMaximizeButtonProperty); }
            set { SetValue(ShowMaximizeButtonProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.ShowMaximizeButton" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.ShowMaximizeButton" /> dependency property.
        /// </value>
        public static readonly DependencyProperty ShowMaximizeButtonProperty =
            DependencyProperty.Register(
            "ShowMaximizeButton",
            typeof(bool),
            typeof(FloatingWindow),
            new PropertyMetadata(true, ShowMaximizeButtonPropertyChanged));

        /// <summary>
        /// ShowMaximizeButtonProperty PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose ShowMaximizeButton property is changed.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
        private static void ShowMaximizeButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FloatingWindow window = (FloatingWindow)d;
            bool visible = window.IsModal ? false : (bool)e.NewValue;

            if (window.maximizeButton != null)
                window.maximizeButton.SetVisible(visible);
        }

        #endregion

        #region public bool ShowMinimizeButton

        /// <summary>
        /// Gets or sets a value indicating whether to show Minimize button.
        /// </summary>
        /// <value><c>true</c> if to show Minimize button; otherwise, <c>false</c>.</value>
        public bool ShowMinimizeButton
        {
            get { return (bool)GetValue(ShowMinimizeButtonProperty); }
            set { SetValue(ShowMinimizeButtonProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.ShowMinimizeButton" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.ShowMinimizeButton" /> dependency property.
        /// </value>
        public static readonly DependencyProperty ShowMinimizeButtonProperty =
            DependencyProperty.Register(
            "ShowMinimizeButton",
            typeof(bool),
            typeof(FloatingWindow),
            new PropertyMetadata(true, ShowMinimizeButtonPropertyChanged));

        /// <summary>
        /// ShowMinimizeButtonProperty PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose ShowMinimizeButton property is changed.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
        private static void ShowMinimizeButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FloatingWindow window = (FloatingWindow)d;
            bool visible = window.IsModal ? false : (bool)e.NewValue;

            if (window.minimizeButton != null)
                window.minimizeButton.SetVisible(visible);
        }

        #endregion

        #region public bool ShowRestoreButton

        /// <summary>
        /// Gets or sets a value indicating whether to show Restore button.
        /// </summary>
        /// <value><c>true</c> if to show Restore button; otherwise, <c>false</c>.</value>
        public bool ShowRestoreButton
        {
            get { return (bool)GetValue(ShowRestoreButtonProperty); }
            set { SetValue(ShowRestoreButtonProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.ShowRestoreButton" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.ShowRestoreButton" /> dependency property.
        /// </value>
        public static readonly DependencyProperty ShowRestoreButtonProperty =
            DependencyProperty.Register(
            "ShowRestoreButton",
            typeof(bool),
            typeof(FloatingWindow),
            new PropertyMetadata(true, ShowRestoreButtonPropertyChanged));

        /// <summary>
        /// ShowRestoreButtonProperty PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose ShowRestoreButton property is changed.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
        private static void ShowRestoreButtonPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FloatingWindow window = (FloatingWindow)d;
            bool visible = window.IsModal ? false : (bool)e.NewValue;

            if (window.restoreButton != null)
                window.restoreButton.SetVisible(visible);
        }

        #endregion

        #region public object Title

        /// <summary>
        /// Gets or sets title content that is displayed on the top of the window. 
        /// Can contain any UI elements - not only a text.
        /// </summary>
        /// <value>
        /// The title displayed at the top of the window. The default is null.
        /// </value>
        public object Title
        {
            get { return GetValue(TitleProperty); }
            set { SetValue(TitleProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.Title" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.Title" /> dependency property.
        /// </value>
        public static readonly DependencyProperty TitleProperty =
            DependencyProperty.Register(
            "Title",
            typeof(object),
            typeof(FloatingWindow),
            null);

        #endregion

        #region public object Icon

        /// <summary>
        /// Gets or sets content that is displayed as an icon of the window on the iconbar. 
        /// </summary>
        /// <value>
        /// The content displayed as an icon of the window on the iconbar. The default is null.
        /// </value>
        public object Icon
        {
            get { return GetValue(IconProperty); }
            set { SetValue(IconProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.Icon" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.Icon" /> dependency property.
        /// </value>
        public static readonly DependencyProperty IconProperty =
            DependencyProperty.Register(
            "Icon",
            typeof(object),
            typeof(FloatingWindow),
            null);

        #endregion

        #region public string IconText

        /// <summary>
        /// Gets or sets a text displayed on the icon of the minimized window.
        /// </summary>
        /// <value>
        /// The text displayed on the icon.
        /// </value>
        public string IconText
        {
            get { return (string)GetValue(IconTextProperty); }
            set { SetValue(IconTextProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.IconText" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.IconText" /> dependency property.
        /// </value>
        public static readonly DependencyProperty IconTextProperty =
            DependencyProperty.Register(
            "IconText",
            typeof(string),
            typeof(FloatingWindow),
            null);

        #endregion

        #region public Brush TitleBackground

        /// <summary>
        /// Gets or sets the title background.
        /// </summary>
        /// <value>The title background.</value>
        public Brush TitleBackground
        {
            get { return (Brush)GetValue(TitleBackgroundProperty); }
            set { SetValue(TitleBackgroundProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.TitleBackground" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.TitleBackground" /> dependency property.
        /// </value>
        public static readonly DependencyProperty TitleBackgroundProperty =
            DependencyProperty.Register(
            "TitleBackground",
            typeof(Brush),
            typeof(FloatingWindow),
            new PropertyMetadata(new SolidColorBrush(Colors.Transparent), null));

        #endregion

        #region public bool ResizeEnabled

        /// <summary>
        /// Gets or sets a value indicating whether resizing is enabled.
        /// </summary>
        /// <value><c>true</c> if resizing is enabled; otherwise, <c>false</c>.</value>
        public bool ResizeEnabled
        {
            get { return (bool)GetValue(ResizeEnabledProperty); }
            set { SetValue(ResizeEnabledProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.ResizeEnabled" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.ResizeEnabled" /> dependency property.
        /// </value>
        public static readonly DependencyProperty ResizeEnabledProperty =
            DependencyProperty.Register(
            "ResizeEnabled",
            typeof(bool),
            typeof(FloatingWindow),
            new PropertyMetadata(true, null));

        #endregion

        #region public double ResizingAreaThickness

        /// <summary>
        /// Gets or sets the width of the resizing area.
        /// </summary>
        /// <value>The width of the resizing area.</value>
        public double ResizingAreaThickness
        {
            get { return (double)GetValue(ResizingAreaThicknessProperty); }
            set { SetValue(ResizingAreaThicknessProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.ResizingAreaThickness" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.ResizingAreaThickness" /> dependency property.
        /// </value>
        public static readonly DependencyProperty ResizingAreaThicknessProperty =
            DependencyProperty.Register(
            "ResizingAreaThickness",
            typeof(double),
            typeof(FloatingWindow),
            new PropertyMetadata(ResizingAreaDefaultValue, OnResizingAreaThicknessPropertyChanged));

        /// <summary>
        /// ResizingAreaThicknessProperty PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose ResizingAreaThickness property is changed.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
        private static void OnResizingAreaThicknessPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FloatingWindow window = (FloatingWindow)d;
            window.resizeController.ResizingArea = (double)e.NewValue;
        }

        #endregion

        #region public Point Position

        /// <summary>
        /// Gets or sets current window position.
        /// </summary>
        /// <value>Current position.</value>
        public Point Position
        {
            get { return (Point)GetValue(PositionProperty); }
            set { SetValue(PositionProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.Position" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.Position" /> dependency property.
        /// </value>
        public static readonly DependencyProperty PositionProperty =
            DependencyProperty.Register(
            "Position",
            typeof(Point),
            typeof(FloatingWindow),
            new PropertyMetadata(new Point(double.NaN, double.NaN), OnPositionPropertyChanged));

        /// <summary>
        /// PositionProperty PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose Position property is changed.</param>
        /// <param name="e">DependencyPropertyChangedEventArgs which contains the old and new values.</param>
        private static void OnPositionPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FloatingWindow window = (FloatingWindow)d;

            if (window != null)
            {
                if (window.FloatingWindowHost.IsLayoutUpdated)
                    window.MoveWindow((Point)e.NewValue);
            }
        }

        #endregion

        #region public bool ShowInIconbar

        /// <summary>
        /// Gets or sets a value indicating whether to show minimized window in the iconbar.
        /// </summary>
        /// <value><c>true</c> if to show minimized window in the iconbar; otherwise, <c>false</c>.</value>
        public bool ShowInIconbar
        {
            get { return (bool)GetValue(ShowInIconbarProperty); }
            set { SetValue(ShowInIconbarProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.ShowInIconbar" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.ShowInIconbar" /> dependency property.
        /// </value>
        public static readonly DependencyProperty ShowInIconbarProperty =
            DependencyProperty.Register(
            "ShowInIconbar",
            typeof(bool),
            typeof(FloatingWindow),
            new PropertyMetadata(true, null));

        #endregion

        #region public FlowDirection FlowDirection

        /// <summary>
        /// Gets or sets the direction that title text flows within window's icon.
        /// </summary>
        /// <value>A constant name from the FlowDirection enumeration, either LeftToRight or RightToLeft.</value>
        public FlowDirection FlowDirection
        {
            get { return (FlowDirection)GetValue(FlowDirectionProperty); }
            set { SetValue(FlowDirectionProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.FlowDirection" /> dependency property.
        /// </summary>
        /// <value>
        /// The identifier for the <see cref="FloatingWindow.FlowDirection" /> dependency property.
        /// </value>
        public static readonly DependencyProperty FlowDirectionProperty =
            DependencyProperty.Register(
            "FlowDirection",
            typeof(FlowDirection),
            typeof(FloatingWindow),
            new PropertyMetadata(FlowDirection.LeftToRight, null));

        #endregion

        #region public Style TitleStyle

        /// <summary>
        /// Gets or sets the style that is used when rendering the Title of the window.
        /// </summary>
        public Style TitleStyle
        {
            get { return GetValue(TitleStyleProperty) as Style; }
            set { SetValue(TitleStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.TitleStyleProperty" /> dependency property.
        /// </summary>
        public static readonly DependencyProperty TitleStyleProperty =
            DependencyProperty.Register(
                "TitleStyle",
                typeof(Style),
                typeof(FloatingWindow),
                new PropertyMetadata(OnTitleStylePropertyChanged));

        /// <summary>
        /// TitleStyle PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose TitleStyle property is changed.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnTitleStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            FloatingWindow window = (FloatingWindow)d;
            if (window != null && window.titleContent != null)
            {
                Style style = e.NewValue as Style;
                window.titleContent.Style = style;
            }
        }

        #endregion

        #region public Style CloseButtonStyle

        /// <summary>
        /// Gets or sets the style of the Close button.
        /// </summary>
        public Style CloseButtonStyle
        {
            get { return GetValue(CloseButtonStyleProperty) as Style; }
            set { SetValue(CloseButtonStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.CloseButtonStyleProperty" /> dependency property.
        /// </summary>
        public static readonly DependencyProperty CloseButtonStyleProperty =
            DependencyProperty.Register(
                "CloseButtonStyle",
                typeof(Style),
                typeof(FloatingWindow),
                new PropertyMetadata(OnCloseButtonStylePropertyChanged));

        /// <summary>
        /// CloseButtonStyle PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose CloseButtonStyle property is changed.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnCloseButtonStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = (FloatingWindow)d;
            if (window != null)
            {
                Style style = e.NewValue as Style;
                window.CloseButtonStyle = style;

                if (window.closeButton != null)
                    window.closeButton.Style = style;
            }
        }

        #endregion

        #region public Style MinimizeButtonStyle

        /// <summary>
        /// Gets or sets the style of the Minimize button.
        /// </summary>
        public Style MinimizeButtonStyle
        {
            get { return GetValue(MinimizeButtonStyleProperty) as Style; }
            set { SetValue(MinimizeButtonStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.MinimizeButtonStyleProperty" /> dependency property.
        /// </summary>
        public static readonly DependencyProperty MinimizeButtonStyleProperty =
            DependencyProperty.Register(
                "MinimizeButtonStyle",
                typeof(Style),
                typeof(FloatingWindow),
                new PropertyMetadata(OnMinimizeButtonStylePropertyChanged));

        /// <summary>
        /// CloseButtonStyle PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose MinimizeButtonStyle property is changed.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnMinimizeButtonStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = (FloatingWindow)d;
            if (window != null)
            {
                Style style = e.NewValue as Style;
                window.CloseButtonStyle = style;

                if (window.minimizeButton != null)
                    window.minimizeButton.Style = style;
            }
        }

        #endregion

        #region public Style MaximizeButtonStyle

        /// <summary>
        /// Gets or sets the style of the Maximize button.
        /// </summary>
        public Style MaximizeButtonStyle
        {
            get { return GetValue(MaximizeButtonStyleProperty) as Style; }
            set { SetValue(MaximizeButtonStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.MaximizeButtonStyleProperty" /> dependency property.
        /// </summary>
        public static readonly DependencyProperty MaximizeButtonStyleProperty =
            DependencyProperty.Register(
                "MaximizeButtonStyle",
                typeof(Style),
                typeof(FloatingWindow),
                new PropertyMetadata(OnMaximizeButtonStylePropertyChanged));

        /// <summary>
        /// MaximizeButtonStyle PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose MaximizeButtonStyle property is changed.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnMaximizeButtonStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = (FloatingWindow)d;
            if (window != null)
            {
                Style style = e.NewValue as Style;
                window.CloseButtonStyle = style;

                if (window.maximizeButton != null)
                    window.maximizeButton.Style = style;
            }
        }

        #endregion

        #region public Style RestoreButtonStyle

        /// <summary>
        /// Gets or sets the style of the Restore button.
        /// </summary>
        public Style RestoreButtonStyle
        {
            get { return GetValue(RestoreButtonStyleProperty) as Style; }
            set { SetValue(RestoreButtonStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the <see cref="FloatingWindow.RestoreButtonStyleProperty" /> dependency property.
        /// </summary>
        public static readonly DependencyProperty RestoreButtonStyleProperty =
            DependencyProperty.Register(
                "RestoreButtonStyle",
                typeof(Style),
                typeof(FloatingWindow),
                new PropertyMetadata(OnRestoreButtonStylePropertyChanged));

        /// <summary>
        /// RestoreButtonStyle PropertyChangedCallback call back static function.
        /// </summary>
        /// <param name="d">FloatingWindow object whose RestoreButtonStyle property is changed.</param>
        /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void OnRestoreButtonStylePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = (FloatingWindow)d;
            if (window != null)
            {
                Style style = e.NewValue as Style;
                window.CloseButtonStyle = style;

                if (window.restoreButton != null)
                    window.restoreButton.Style = style;
            }
        }

        #endregion

        #region public bool? DialogResult

        /// <summary>
        /// Gets or sets a value that indicates whether the FloatingWindow was accepted or canceled.
        /// </summary>
        /// <value>true if the FloatingWindow was accepted; false - if canceled. The default is null.</value>
        [TypeConverter(typeof(NullableBoolConverter))]
        public bool? DialogResult { get; set; }

        #endregion

        #region Member Fields

        // Mouse click point
        private Point clickPoint;

        // Window position when the mouse was clicked
        private Point clickWindowPosition;

        // Window position, size and state when it was maximized or minimized
        private Point previousPosition;
        private Size previousSize;
        private WindowState previousWindowState;

        private Thickness contentBorderThickness;
        private CornerRadius contentBorderCornerRadius;
        private CornerRadius chromeBorderCornerRadius;

        private Storyboard openingStoryboard;
        private Storyboard closingStoryboard;
        private Storyboard inertialMotionStoryboard;

        private FrameworkElement root;
        private FrameworkElement contentPresenter;
        private FrameworkElement contentRoot;
        private FrameworkElement chrome;
        private ContentControl titleContent;
        private Border contentBorder;

        private ButtonBase closeButton;
        private ButtonBase maximizeButton;
        private ButtonBase restoreButton;
        private ButtonBase minimizeButton;

        private bool isAppExit;
        private bool isMouseCaptured;

        private ResizeController resizeController;
        private ISnapinController snapinController;
        private InertiaController inertiaController;
        private ILocalStorage localStorage;
        private IBitmapHelper bitmapHelper;

        // Current window state
        private WindowState windowState = WindowState.Normal;

        // Specifies whether the window is moving or resizing
        private WindowAction windowAction;

        // Bitmap containing thumbnail image
        private ImageSource minimizedWindowThumbnail;

        #endregion Member Fields

        /// <summary>
        /// Initializes a new instance of the <see cref="FloatingWindow" /> class.
        /// </summary>
        public FloatingWindow()
        {
            DefaultStyleKey = typeof(FloatingWindow);

            resizeController = new ResizeController(this);
            resizeController.ResizingArea = ResizingAreaThickness;
            snapinController = new SnapinController();
            inertiaController = new InertiaController();
            localStorage = new LocalStorage();
            bitmapHelper = new BitmapHelper();

            this.SetVisible(false);
        }

        #region Events

        /// <summary>
        /// Occurs when the <see cref="FloatingWindow" /> is activated.
        /// </summary>
        /// <remarks>Not visible <see cref="FloatingWindow" /> cannot be the active. </remarks>
        public event EventHandler Activated;

        /// <summary>
        /// Occurs when the <see cref="FloatingWindow" /> is deactivated.
        /// </summary>
        public event EventHandler Deactivated;

        /// <summary>
        /// Occurs when the <see cref="FloatingWindow" /> is closed.
        /// </summary>
        public event EventHandler Closed;

        /// <summary>
        /// Occurs when the <see cref="FloatingWindow" /> is maximized.
        /// </summary>
        public event EventHandler Maximized;

        /// <summary>
        /// Occurs when the <see cref="FloatingWindow" /> is minimized.
        /// </summary>
        public event EventHandler Minimized;

        /// <summary>
        /// Occurs when the <see cref="FloatingWindow" /> is restored.
        /// </summary>
        public event EventHandler Restored;

        /// <summary>
        /// Occurs when the <see cref="FloatingWindow" /> is closing.
        /// </summary>
        public event EventHandler<CancelEventArgs> Closing;

        #endregion Events

        #region Properties

        /// <summary>
        /// Gets or sets a reference to the FloatingWindowHost, containing the window.
        /// </summary>
        /// <value>The floating window host.</value>
        public FloatingWindowHost FloatingWindowHost { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the window is always displayed in front of other windows.
        /// </summary>
        /// <value><c>true</c> if top most; otherwise, <c>false</c>.</value>
        public bool TopMost { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether this window is open.
        /// </summary>
        /// <value><c>true</c> if this window is open; otherwise, <c>false</c>.</value>
        public bool IsOpen { get; private set; }

        /// <summary>
        /// Gets or sets a value indicating whether this window is modal.
        /// </summary>
        /// <value><c>true</c> if this window is modal; otherwise, <c>false</c>.</value>
        public bool IsModal { get; private set; }

        /// <summary>
        /// Gets the window thumbnail.
        /// </summary>
        /// <value>The window thumbnail.</value>
        public ImageSource WindowThumbnail
        {
            get
            {
                return (windowState == WindowState.Minimized) ? minimizedWindowThumbnail : GetThumbnailImage();
            }
        }

        /// <summary>
        /// Gets the state of the window.
        /// </summary>
        /// <value>Current state of the window.</value>
        public WindowState WindowState
        {
            get { return windowState; }
        }

        /// <summary>
        /// Gets or sets the minimum height constraint of a <see cref="T:System.Windows.FrameworkElement"/>.
        /// </summary>
        /// <value>he minimum height of the window.</value>
        /// <returns>The minimum height of the window, in pixels. The default is 0. 
        /// This value can be any value equal to or greater than 0. 
        /// However, <see cref="F:System.Double.PositiveInfinity"/> is not valid.</returns>
        public new double MinHeight
        {
            get
            {
                double minHeight = base.MinHeight;

                if ((base.MinHeight.IsNotSet() || base.MinHeight == 0) &&
                    (chrome != null && contentRoot != null))
                {
                    // Set minimal height to the height of the chrome element of the window
                    minHeight = chrome.GetRelativePosition(contentRoot).Y + chrome.ActualHeight;
                }

                return minHeight;
            }

            set
            {
                base.MinHeight = value;
            }
        }

        /// <summary>
        /// Gets a bounding rectangle of the window.
        /// </summary>
        /// <value>Bounding rectangle.</value>
        public Rect BoundingRectangle
        {
            get { return new Rect(Position.X, Position.Y, ActualWidth, ActualHeight); }
        }

        /// <summary>
        /// Gets a Snapin controller.
        /// </summary>
        /// <value>Snapin controller.</value>
        public ISnapinController SnapinController
        {
            get { return snapinController; }
        }

        /// <summary>
        /// Gets the host panel, containing the floating windows.
        /// </summary>
        /// <value>The host panel.</value>
        public Panel HostPanel
        {
            get { return this.FloatingWindowHost == null ? null : this.FloatingWindowHost.HostPanel; }
        }

        /// <summary>
        /// Gets a value indicating whether window size is explicitly set.
        /// </summary>
        /// <value><c>true</c> if window size is set; otherwise, <c>false</c>.</value>
        private bool IsWindowSizeSet
        {
            get { return !Width.IsNotSet() && !Height.IsNotSet(); }
        }

        /// <summary>
        /// Gets a value indicating whether the window Tag property is set.
        /// </summary>
        /// <value><c>true</c> if the Tag set; otherwise, <c>false</c>.</value>
        private bool IsWindowTagSet
        {
            get
            {
                string tag = this.Tag as string;
                return !string.IsNullOrWhiteSpace(tag);
            }
        }

        /// <summary>
        /// Gets coordinates of the window placed in the center of its host.
        /// </summary>
        /// <value>The centered window position.</value>
        private Point CenteredWindowPosition
        {
            get
            {
                return new Point((HostPanel.ActualWidth - Width.ValueOrZero()) / 2, (HostPanel.ActualHeight - Height.ValueOrZero()) / 2);
            }
        }

        #endregion Properties

        /// <summary>
        /// Shows the window as a modal one.
        /// </summary>
        public void ShowModal()
        {
            IsModal = true;
            Position = new Point(double.NaN, double.NaN);
            ShowMaximizeButton = false;
            ShowMinimizeButton = false;

            Show();
        }

        /// <summary>
        /// Opens the <see cref="FloatingWindow" /> in previously saved position or
        /// in the center of the <see cref="FloatingWindowHost" />.
        /// </summary>
        public void Show()
        {
            Show(Position);
        }

        /// <summary>
        /// Shows the window in the specified coordinates, relative to the window's Host.
        /// </summary>
        /// <param name="x">X-coordinate.</param>
        /// <param name="y">Y-coordinate.</param>
        public void Show(double x, double y)
        {
            Show(new Point(x, y));
        }

        /// <summary>
        /// Shows a <see cref="FloatingWindow"/> at maximal size taking into account
        /// specified margins and current <see cref="FloatingWindowHost"/> size.
        /// </summary>
        /// <param name="margins">Window margins.</param>
        public void Show(Thickness margins)
        {
            CheckHost();
            Action<Thickness> action = new Action<Thickness>(ShowWindow);
            this.FloatingWindowHost.ShowWindow(action, margins);
        }

        /// <summary>
        /// Shows the window in the specified coordinates, relative to the window's Host.
        /// </summary>
        /// <param name="point">Coordinates of the upper-left corner of the window.</param>
        public void Show(Point point)
        {
            CheckHost();
            Action<Point> action = new Action<Point>(ShowWindow);
            this.FloatingWindowHost.ShowWindow(action, point);
        }

        /// <summary>
        /// Shows a <see cref="FloatingWindow"/> at maximal size taking into account
        /// specified margins and current <see cref="FloatingWindowHost"/> size.
        /// </summary>
        /// <param name="margins">Window margins.</param>
        private void ShowWindow(Thickness margins)
        {
            Width = Math.Max(MinWidth, HostPanel.ActualWidth - margins.Horizontal());
            Height = Math.Max(MinHeight, HostPanel.ActualHeight - margins.Vertical());

            ShowWindow(new Point(margins.Left, margins.Top));
        }

        /// <summary>
        /// Shows the window in the specified coordinates, relative to the window's Host.
        /// </summary>
        /// <param name="point">Coordinates of the upper-left corner of the window.</param>
        /// <exception cref="System.InvalidOperationException">"The FloatingWindow was not added to the host.</exception>
        private void ShowWindow(Point point)
        {
            if (!IsOpen)
            {
                if (IsModal)
                    this.FloatingWindowHost.ShowWindowAsModal(this);

                SubscribeToEvents();
                SubscribeToTemplatePartEvents();
                SubscribeToStoryBoardEvents();

                // Guarantee that the visual tree of an element is complete
                ApplyTemplate();

                // Brings current window to the front
                SetTopmost();

                Point position = point;

                if (point.IsNotSet())
                    position = CenteredWindowPosition;

                MoveWindow(position);
                this.SetVisible(true);

                if (!IsWindowSizeSet && point.IsNotSet())
                {
                    // If window size is not set explicitly we should wait
                    // when the window layout is updated and update its position
                    contentRoot.SizeChanged += new SizeChangedEventHandler(ContentRoot_SizeChanged);
                }

                VisualStateManager.GoToState(this, VSMSTATE_StateOpen, true);
                IsOpen = true;
            }
            else
            {
                MoveWindow(point);
                this.SetVisible(true);
            }
        }

        /// <summary>
        /// Handles the SizeChanged event of the ContentRoot control to update window position 
        /// only once when the window is opened.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.SizeChangedEventArgs"/> instance containing the event data.</param>
        private void ContentRoot_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            contentRoot.SizeChanged -= new SizeChangedEventHandler(ContentRoot_SizeChanged);
            double dx = -(e.NewSize.Width.ValueOrZero() - e.PreviousSize.Width.ValueOrZero()) / 2;
            double dy = -(e.NewSize.Height.ValueOrZero() - e.PreviousSize.Height.ValueOrZero()) / 2;
            Point point = Position.Add(dx, dy);
            MoveWindow(point);
        }

        /// <summary>
        /// Restores window state, size and its position.
        /// </summary>
        public void RestoreWindow()
        {
            switch (windowState)
            {
                case WindowState.Minimized:
                    if (previousWindowState == WindowState.Maximized)
                    {
                        Width = HostPanel.ActualWidth;
                        Height = HostPanel.ActualHeight;
                    }

                    SetTopmost();
                    windowState = previousWindowState;
                    VisualStateManager.GoToState(this, VSMSTATE_StateRestored, true);
                    OnRestored(EventArgs.Empty);
                    break;

                case WindowState.Normal:
                    SetTopmost();
                    EnsureVisible();
                    break;

                case WindowState.Maximized:
                    SetTopmost();
                    break;
            }

            Focus();
        }

        /// <summary>
        /// Makes the window topmost and tries to set focus on it.
        /// </summary>
        public void Activate()
        {
            SetTopmost();
        }

        /// <summary>
        /// Brings current window to the front.
        /// </summary>
        private void SetTopmost()
        {
            if (this.FloatingWindowHost != null)
                this.FloatingWindowHost.SetTopmostWindow(this);
        }

        /// <summary>
        /// Ensures the window is visible.
        /// </summary>
        private void EnsureVisible()
        {
            if (HostPanel != null && (Position.X >= HostPanel.ActualWidth || Position.Y >= HostPanel.ActualHeight))
            {
                Position = CenteredWindowPosition;
            }
        }

        /// <summary>
        /// Executed when the application is exited.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">Event args.</param>
        private void Application_Exit(object sender, EventArgs e)
        {
            if (IsOpen)
            {
                isAppExit = true;
                try
                {
                    Close();
                }
                finally
                {
                    isAppExit = false;
                }
            }
        }

        /// <summary>
        /// Closes a <see cref="FloatingWindow" />.
        /// </summary>
        public void Close()
        {
            SaveSizeAndPosition();

            CancelEventArgs e = new CancelEventArgs();
            OnClosing(e);

            // On ApplicationExit, Close() cannot be cancelled
            if (IsOpen && (!e.Cancel || isAppExit))
            {
                IsOpen = false;

                if (IsModal)
                    this.FloatingWindowHost.RemoveOverlay();

                if (closingStoryboard != null)
                {
                    VisualStateManager.GoToState(this, VSMSTATE_StateClosed, true);
                }
                else
                {
                    this.Visibility = Visibility.Collapsed;
                    OnClosed(EventArgs.Empty);
                }

                UnSubscribeFromEvents();
                UnsubscribeFromTemplatePartEvents();
            }
        }

        /// <summary>
        /// Restores the size and position stored in the IsolatedStorage on closing.
        /// </summary>
        public void RestoreSizeAndPosition()
        {
            if (IsWindowTagSet)
            {
                string positionKey = GetAppSettingsKey("Position");
                string sizeKey = GetAppSettingsKey("Size");

                if (localStorage.Contains(positionKey))
                    Position = (Point)localStorage[positionKey];

                if (localStorage.Contains(sizeKey))
                {
                    Size size = (Size)localStorage[sizeKey];
                    Width = size.Width == 0 ? double.NaN : size.Width;
                    Height = size.Height == 0 ? double.NaN : size.Height;
                }
            }
        }

        /// <summary>
        /// Executed when the Close button is clicked.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Routed event args.</param>
        private void CloseButton_Click(object sender, RoutedEventArgs e)
        {
            Close();
        }

        /// <summary>
        /// Executed when the Closing storyboard ends.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event args.</param>
        private void Closing_Completed(object sender, EventArgs e)
        {
            if (closingStoryboard != null)
                closingStoryboard.Completed -= new EventHandler(Closing_Completed);

            this.Visibility = Visibility.Collapsed;
            OnClosed(EventArgs.Empty);
        }

        /// <summary>
        /// Builds the visual tree for the <see cref="FloatingWindow" /> control 
        /// when a new template is applied.
        /// </summary>
        public override void OnApplyTemplate()
        {
            UnsubscribeFromTemplatePartEvents();
            UnsubscribeFromStoryBoardEvents();

            base.OnApplyTemplate();

            root = GetTemplateChild(PART_Root) as FrameworkElement;
            contentRoot = GetTemplateChild(PART_ContentRoot) as FrameworkElement;
            contentBorder = GetTemplateChild(PART_ContentBorder) as Border;
            chrome = GetTemplateChild(PART_Chrome) as FrameworkElement;
            titleContent = GetTemplateChild(PART_TitleContent) as ContentControl;
            contentPresenter = GetTemplateChild(PART_ContentPresenter) as FrameworkElement;
            closeButton = GetTemplateChild(PART_CloseButton) as ButtonBase;
            maximizeButton = GetTemplateChild(PART_MaximizeButton) as ButtonBase;
            minimizeButton = GetTemplateChild(PART_MinimizeButton) as ButtonBase;
            restoreButton = GetTemplateChild(PART_RestoreButton) as ButtonBase;

            if (root == null)
                throw new NotImplementedException("Template Part PART_Root is required to display FloatingWindow.");

            if (contentRoot == null)
                throw new NotImplementedException("Template Part PART_ContentRoot is required to display FloatingWindow.");

            if (contentPresenter == null)
                throw new NotImplementedException("Template Part PART_ContentPresenter is required to display FloatingWindow.");

            SetStyles();
            GetStoryboards();
            SetInitialRootPosition();
            InitializeContentRootTransformGroup();

            if (closeButton != null)
                closeButton.SetVisible(ShowCloseButton);

            if (minimizeButton != null)
                minimizeButton.SetVisible(ShowMinimizeButton);

            if (maximizeButton != null)
                maximizeButton.SetVisible(ShowMaximizeButton);

            SubscribeToTemplatePartEvents();
            SubscribeToStoryBoardEvents();
        }

        /// <summary>
        /// Sets styles that are applied for different template parts.
        /// </summary>
        private void SetStyles()
        {
            if (titleContent != null && this.TitleStyle != null)
                titleContent.Style = this.TitleStyle;

            if (minimizeButton != null && this.MinimizeButtonStyle != null)
                minimizeButton.Style = this.MinimizeButtonStyle;

            if (maximizeButton != null && this.MaximizeButtonStyle != null)
                maximizeButton.Style = this.MaximizeButtonStyle;

            if (restoreButton != null && this.RestoreButtonStyle != null)
                restoreButton.Style = this.RestoreButtonStyle;

            if (closeButton != null && this.CloseButtonStyle != null)
                closeButton.Style = this.CloseButtonStyle;
        }

        /// <summary>
        /// Gets the storyboards defined in the <see cref="FloatingWindow" /> style.
        /// </summary>
        private void GetStoryboards()
        {
            if (root != null)
            {
                var groups = VisualStateManager.GetVisualStateGroups(root) as Collection<VisualStateGroup>;
                if (groups != null)
                {
                    var states = (from stategroup in groups
                                  where stategroup.Name == FloatingWindow.VSMGROUP_Window
                                  select stategroup.States).FirstOrDefault() as Collection<VisualState>;

                    if (states != null)
                    {
                        closingStoryboard = (from state in states
                                             where state.Name == FloatingWindow.VSMSTATE_StateClosed
                                             select state.Storyboard).FirstOrDefault();

                        openingStoryboard = (from state in states
                                             where state.Name == FloatingWindow.VSMSTATE_StateOpen
                                             select state.Storyboard).FirstOrDefault();
                    }
                }

                if (inertialMotionStoryboard == null)
                    inertialMotionStoryboard = new Storyboard();
            }
        }

        /// <summary>
        /// Shift the root of the window to compensate its margins.
        /// </summary>
        private void SetInitialRootPosition()
        {
            double x = Math.Round(-this.Margin.Left);
            double y = Math.Round(-this.Margin.Top);

            var transformGroup = root.RenderTransform as TransformGroup;
            if (transformGroup == null)
            {
                transformGroup = new TransformGroup();
                transformGroup.Children.Add(root.RenderTransform);
                root.RenderTransform = transformGroup;
            }

            var translateTransform = transformGroup.Children.OfType<TranslateTransform>().FirstOrDefault();
            if (translateTransform == null)
            {
                transformGroup.Children.Add(new TranslateTransform() { X = x, Y = y });
            }
            else
            {
                translateTransform.X = x;
                translateTransform.Y = y;
            }
        }

        /// <summary>
        /// Checks the TransformGroup of the content root or creates it if necesary.
        /// </summary>
        private void InitializeContentRootTransformGroup()
        {
            var transformGroup = contentRoot.RenderTransform as TransformGroup;
            if (transformGroup == null)
            {
                transformGroup = new TransformGroup();
                transformGroup.Children.Add(contentRoot.RenderTransform);
                contentRoot.RenderTransform = transformGroup;
            }

            // Check that ScaleTransform exists in the TransformGroup
            // ScaleTransform is used as a target in Storyboards 
            var scaleTransform = transformGroup.Children.OfType<ScaleTransform>().FirstOrDefault();

            if (scaleTransform == null)
                transformGroup.Children.Insert(0, new ScaleTransform());

            var translateTransform = transformGroup.Children.OfType<TranslateTransform>().FirstOrDefault();

            if (translateTransform == null)
                transformGroup.Children.Add(new TranslateTransform());
        }

        /// <summary>
        /// Raises the <see cref="FloatingWindow.Activated" /> event.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected virtual void OnActivated(EventArgs e)
        {
            EventHandler handler = Activated;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="FloatingWindow.Deactivated" /> event.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected virtual void OnDeactivated(EventArgs e)
        {
            EventHandler handler = Deactivated;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="FloatingWindow.Closed" /> event.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected virtual void OnClosed(EventArgs e)
        {
            this.FloatingWindowHost.Remove(this);
            this.FloatingWindowHost.ActivateTopmostWindow();
            UnsubscribeFromStoryBoardEvents();

            EventHandler handler = Closed;
            if (handler != null)
            {
                handler(this, e);
            }

            Dispose();
        }

        /// <summary>
        /// Raises the <see cref="FloatingWindow.Closing" /> event.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected virtual void OnClosing(CancelEventArgs e)
        {
            EventHandler<CancelEventArgs> handler = Closing;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="FloatingWindow.Maximized" /> event.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected virtual void OnMaximized(EventArgs e)
        {
            EventHandler handler = Maximized;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="FloatingWindow.Minimized" /> event.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected virtual void OnMinimized(EventArgs e)
        {
            EventHandler handler = Minimized;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        /// <summary>
        /// Raises the <see cref="FloatingWindow.Restored" /> event.
        /// </summary>
        /// <param name="e">The event data.</param>
        protected virtual void OnRestored(EventArgs e)
        {
            EventHandler handler = Restored;
            if (handler != null)
            {
                handler(this, e);
            }
        }

        /// <summary>
        /// This method is called every time a <see cref="FloatingWindow" /> is displayed.
        /// </summary>
        protected virtual void OnOpened()
        {
            if (!Focus())
            {
                // If the Focus() fails it means there is no focusable element in the window.
                // In this case we set IsTabStop to true to have the keyboard functionality
                IsTabStop = true;
                Focus();
            }
        }

        /// <summary>
        /// Executed when the opening storyboard finishes.
        /// </summary>
        /// <param name="sender">Sender object.</param>
        /// <param name="e">Event args.</param>
        private void Opening_Completed(object sender, EventArgs e)
        {
            if (openingStoryboard != null)
                openingStoryboard.Completed -= new EventHandler(Opening_Completed);

            this.FloatingWindowHost.UpdateIconBar();
            IsOpen = true;
            OnOpened();
        }

        /// <summary>
        /// Subscribes to events when the window is opened.
        /// </summary>
        private void SubscribeToEvents()
        {
            if (Application.Current != null)
                Application.Current.Exit += new EventHandler(Application_Exit);

            if (this.FloatingWindowHost != null)
            {
                this.FloatingWindowHost.SizeChanged += new SizeChangedEventHandler(Host_SizeChanged);
                this.FloatingWindowHost.ActiveWindowChanged += new EventHandler<ActiveWindowChangedEventArgs>(ActiveWindowChanged);
            }

            // Attach Mouse event handler to catch already handled events to bring the window to the front
            this.AddHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(FloatingWindow_MouseLeftButtonDown), true);
        }

        /// <summary>
        /// Handles the MouseLeftButtonDown event to bring the window to the front.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void FloatingWindow_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            // Gets the element with keyboard focus
            Control elementWithFocus = FocusManager.GetFocusedElement() as Control;

            // Brings current window to the front
            SetTopmost();

            if (elementWithFocus != null)
            {
                if (IsControlInVisualTree(elementWithFocus))
                {
                    elementWithFocus.Focus();
                }
                else
                {
                    // Try to set focus on the window
                    Focus();
                }
            }

            // Stop any inertial motion
            StopInertialMotion();
        }

        /// <summary>
        /// Determines whether the control is in the visual tree of the window.
        /// </summary>
        /// <param name="control">The control to test.</param>
        /// <returns>
        /// <c>true</c> if the control is in the visual tree; otherwise, <c>false</c>.
        /// </returns>
        private bool IsControlInVisualTree(Control control)
        {
            if (control != null)
            {
                DependencyObject parent = control;
                do
                {
                    parent = VisualTreeHelper.GetParent(parent);
                    FloatingWindow window = parent as FloatingWindow;

                    if (window != null && window == this)
                        return true;
                }
                while (parent != null);
            }

            return false;
        }

        /// <summary>
        /// Unsubscribe from events when the ChildWindow is closed.
        /// </summary>
        private void UnSubscribeFromEvents()
        {
            if (Application.Current != null)
                Application.Current.Exit -= new EventHandler(Application_Exit);

            if (this.FloatingWindowHost != null)
            {
                this.FloatingWindowHost.SizeChanged -= new SizeChangedEventHandler(Host_SizeChanged);
                this.FloatingWindowHost.ActiveWindowChanged -= new EventHandler<ActiveWindowChangedEventArgs>(ActiveWindowChanged);
            }

            this.RemoveHandler(UIElement.MouseLeftButtonDownEvent, new MouseButtonEventHandler(FloatingWindow_MouseLeftButtonDown));
        }

        /// <summary>
        /// Subscribes to the events on the storyboards. 
        /// </summary>
        private void SubscribeToStoryBoardEvents()
        {
            if (closingStoryboard != null)
                closingStoryboard.Completed += new EventHandler(Closing_Completed);

            if (openingStoryboard != null)
                openingStoryboard.Completed += new EventHandler(Opening_Completed);

            if (inertialMotionStoryboard != null)
                inertialMotionStoryboard.Completed += new EventHandler(InertialMotion_Completed);
        }

        /// <summary>
        /// Unsubscribe from events that are subscribed on the storyboards. 
        /// </summary>
        private void UnsubscribeFromStoryBoardEvents()
        {
            if (closingStoryboard != null)
                closingStoryboard.Completed -= new EventHandler(Closing_Completed);

            if (openingStoryboard != null)
                openingStoryboard.Completed -= new EventHandler(Opening_Completed);

            if (inertialMotionStoryboard != null)
                inertialMotionStoryboard.Completed -= new EventHandler(InertialMotion_Completed);
        }

        /// <summary>
        /// Subscribes to the events on the template parts.
        /// </summary>
        private void SubscribeToTemplatePartEvents()
        {
            if (closeButton != null)
                closeButton.Click += new RoutedEventHandler(CloseButton_Click);

            if (maximizeButton != null)
                maximizeButton.Click += new RoutedEventHandler(MaximizeButton_Click);

            if (restoreButton != null)
                restoreButton.Click += new RoutedEventHandler(RestoreButton_Click);

            if (minimizeButton != null)
                minimizeButton.Click += new RoutedEventHandler(MinimizeButton_Click);
        }

        /// <summary>
        /// Unsubscribe from the events that are subscribed on the template part elements.
        /// </summary>
        private void UnsubscribeFromTemplatePartEvents()
        {
            if (closeButton != null)
                closeButton.Click -= new RoutedEventHandler(CloseButton_Click);

            if (maximizeButton != null)
                maximizeButton.Click -= new RoutedEventHandler(MaximizeButton_Click);

            if (restoreButton != null)
                restoreButton.Click -= new RoutedEventHandler(RestoreButton_Click);

            if (minimizeButton != null)
                minimizeButton.Click -= new RoutedEventHandler(MinimizeButton_Click);
        }

        /// <summary>
        /// Handles the ActiveWindowChanged event of the Host control.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="SilverFlow.Controls.ActiveWindowChangedEventArgs"/> instance containing the event data.</param>
        private void ActiveWindowChanged(object sender, ActiveWindowChangedEventArgs e)
        {
            if (e.Old == this)
                OnDeactivated(EventArgs.Empty);

            if (e.New == this)
                OnActivated(EventArgs.Empty);
        }

        /// <summary>
        /// Handles the Click event of the MaximizeButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void MaximizeButton_Click(object sender, RoutedEventArgs e)
        {
            MaximizeWindow();
        }

        /// <summary>
        /// Handles the Click event of the RestoreButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void RestoreButton_Click(object sender, RoutedEventArgs e)
        {
            RestoreMaximizedWindow();
        }

        /// <summary>
        /// Handles the Click event of the MinimizeButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void MinimizeButton_Click(object sender, RoutedEventArgs e)
        {
            MinimizeWindow();
        }

        /// <summary>
        /// Minimizes the window.
        /// </summary>
        private void MinimizeWindow()
        {
            if (windowState != WindowState.Minimized)
            {
                if (minimizeButton != null)
                    VisualStateManager.GoToState(minimizeButton, VSMSTATE_StateNormal, true);

                if (windowState == WindowState.Normal)
                {
                    // Store previous coordinates
                    previousPosition = Position;
                    previousSize = new Size(ActualWidth, ActualHeight);
                }

                minimizedWindowThumbnail = GetThumbnailImage();

                previousWindowState = windowState;
                VisualStateManager.GoToState(this, VSMSTATE_StateMinimized, true);
                OnMinimized(EventArgs.Empty);
            }

            windowState = WindowState.Minimized;
            OnDeactivated(EventArgs.Empty);

            this.FloatingWindowHost.ActivateTopmostWindow();
        }

        /// <summary>
        /// Creates a thumbnail of the window.
        /// </summary>
        /// <returns>Bitmap containing thumbnail image.</returns>
        private ImageSource GetThumbnailImage()
        {
            // If an Icon is specified - use it as a thumbnail displayed on the iconbar
            // Otherwise, display the window itself
            FrameworkElement icon = (Icon as FrameworkElement) ?? contentRoot;
            ImageSource bitmap = bitmapHelper.RenderVisual(icon, FloatingWindowHost.IconWidth, FloatingWindowHost.IconHeight);

            return bitmap;
        }

        /// <summary>
        /// Maximizes the window.
        /// </summary>
        public void MaximizeWindow()
        {
            if (windowState != WindowState.Maximized)
            {
                if (maximizeButton != null && restoreButton != null && HostPanel != null)
                {
                    if (this.ShowMaximizeButton)
                        maximizeButton.SetVisible(false);

                    if (this.ShowRestoreButton)
                        restoreButton.SetVisible(true);

                    VisualStateManager.GoToState(restoreButton, VSMSTATE_StateNormal, true);

                    // Store previous coordinates
                    previousPosition = Position;
                    previousSize = new Size(ActualWidth, ActualHeight);

                    // Hide the outer border
                    if (contentBorder != null)
                    {
                        contentBorderThickness = contentBorder.BorderThickness;
                        contentBorderCornerRadius = contentBorder.CornerRadius;
                        contentBorder.BorderThickness = new Thickness(0);
                        contentBorder.CornerRadius = new CornerRadius(0);
                    }

                    Border border = chrome as Border;
                    if (border != null)
                    {
                        chromeBorderCornerRadius = border.CornerRadius;
                        border.CornerRadius = new CornerRadius(0);
                    }

                    StartMaximizingAnimation();
                }

                previousWindowState = windowState;
                windowState = WindowState.Maximized;
            }
        }

        /// <summary>
        /// Checks if the floating window was added to the FloatingWindowHost.
        /// </summary>
        private void CheckHost()
        {
            if (this.FloatingWindowHost == null)
                throw new InvalidOperationException("The FloatingWindow was not added to the FloatingWindowHost.");
        }

        /// <summary>
        /// Starts maximizing animation.
        /// </summary>
        private void StartMaximizingAnimation()
        {
            SaveActualSize();

            this.MoveAndResize(new Point(0, 0), HostPanel.ActualWidth, HostPanel.ActualHeight,
                MaximizingDurationInMilliseconds, Maximizing_Completed);
        }

        /// <summary>
        /// Saves the actual size if it was not set explicitly set. 
        /// E.g. the Width can be NaN, that means "Auto".
        /// </summary>
        private void SaveActualSize()
        {
            if (Width.IsNotSet())
                Width = ActualWidth;

            if (Height.IsNotSet())
                Height = ActualHeight;
        }

        /// <summary>
        /// Handles the Completed event of the Maximizing animation.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Maximizing_Completed(object sender, EventArgs e)
        {
            OnMaximized(EventArgs.Empty);
        }

        /// <summary>
        /// Restores maximized window position and size.
        /// </summary>
        private void RestoreMaximizedWindow()
        {
            if (windowState != WindowState.Normal)
            {
                if (maximizeButton != null && restoreButton != null && HostPanel != null)
                {
                    if (this.ShowMaximizeButton)
                        maximizeButton.SetVisible(true);

                    if (this.ShowRestoreButton)
                        restoreButton.SetVisible(false);

                    VisualStateManager.GoToState(maximizeButton, VSMSTATE_StateNormal, true);
                }

                // Restore the outer border
                if (contentBorder != null)
                {
                    contentBorder.BorderThickness = contentBorderThickness;
                    contentBorder.CornerRadius = contentBorderCornerRadius;
                }

                Border border = chrome as Border;

                if (border != null)
                    border.CornerRadius = chromeBorderCornerRadius;

                StartRestoringAnimation();
                windowState = WindowState.Normal;
            }
            else
            {
                Show(Position);
            }
        }

        /// <summary>
        /// Starts restoring animation.
        /// </summary>
        private void StartRestoringAnimation()
        {
            SaveActualSize();

            this.MoveAndResize(previousPosition, previousSize.Width, previousSize.Height,
                RestoringDurationInMilliseconds, Restoring_Completed);
        }

        /// <summary>
        /// Handles the Completed event of the Restoring animation.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Restoring_Completed(object sender, EventArgs e)
        {
            OnRestored(EventArgs.Empty);
        }

        /// <summary>
        /// Updates clipping region on host SizeChanged event.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.SizeChangedEventArgs"/> instance containing the event data.</param>
        private void Host_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (windowState == WindowState.Maximized)
            {
                Width = HostPanel.ActualWidth;
                Height = double.IsInfinity(MaxHeight) ? HostPanel.ActualHeight : MaxHeight;
            }
        }

        /// <summary>
        /// Executed when mouse left button is down.
        /// </summary>
        /// <param name="e">The data for the event.</param>
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonDown(e);

            if (windowState == WindowState.Normal)
            {
                // Stop inertial motion before the mouse is captured
                StopInertialMotion();

                clickPoint = e.GetPosition(HostPanel);
                clickWindowPosition = Position;
                snapinController.SnapinDistance = this.FloatingWindowHost.SnapinDistance;
                snapinController.SnapinMargin = this.FloatingWindowHost.SnapinMargin;
                snapinController.SnapinEnabled = this.FloatingWindowHost.SnapinEnabled;

                if (ResizeEnabled && resizeController.CanResize)
                {
                    snapinController.SnapinBounds = this.FloatingWindowHost.GetSnapinBounds(this);
                    resizeController.StartResizing();
                    CaptureMouseCursor();
                    windowAction = WindowAction.Resize;
                }
                else if (chrome != null)
                {
                    // If the mouse was clicked on the chrome - start dragging the window
                    Point point = e.GetPosition(chrome);

                    if (chrome.ContainsPoint(point))
                    {
                        snapinController.SnapinBounds = this.FloatingWindowHost.GetSnapinBounds(this);
                        CaptureMouseCursor();
                        windowAction = WindowAction.Move;
                        inertiaController.StartMotion(Position);
                    }
                }
            }
        }

        /// <summary>
        /// Executed when mouse left button is up.
        /// </summary>
        /// <param name="e">The data for the event.</param>
        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            base.OnMouseLeftButtonUp(e);

            if (windowAction == WindowAction.Move)
            {
                InertialMotion motion = inertiaController.GetInertialMotionParameters(
                    this.FloatingWindowHost.HostPanel.GetActualBoundingRectangle(), this.BoundingRectangle);

                if (motion != null)
                {
                    contentRoot.AnimateTranslateTransform(inertialMotionStoryboard, motion.EndPosition, motion.Seconds, motion.EasingFunction);
                }
            }

            if (isMouseCaptured)
            {
                contentRoot.ReleaseMouseCapture();
                isMouseCaptured = false;
            }

            windowAction = WindowAction.None;
        }

        /// <summary>
        /// Handles the Completed event of the InertialMotionStoryboard.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void InertialMotion_Completed(object sender, EventArgs e)
        {
            // Save current window position reading it from the TranslateTransform object
            Position = GetCurrentWindowPosition();
        }

        /// <summary>
        /// Stops current inertial motion.
        /// </summary>
        private void StopInertialMotion()
        {
            if (inertialMotionStoryboard.GetCurrentState() != ClockState.Stopped)
            {
                inertialMotionStoryboard.Pause();

                // The Position has rounded coordinates now, but real X and Y coordinates are fractional
                Position = GetCurrentWindowPosition();

                // Move the window to the rounded coordinates
                MoveWindow(Position);

                inertialMotionStoryboard.Stop();
                inertialMotionStoryboard.Children.Clear();
            }
        }

        /// <summary>
        /// Gets current window position taking into account animation effects.
        /// </summary>
        /// <returns>Current window position.</returns>
        private Point GetCurrentWindowPosition()
        {
            var transformGroup = contentRoot.RenderTransform as TransformGroup;
            var translateTransform = transformGroup.Children.OfType<TranslateTransform>().FirstOrDefault();
            var position = new Point(translateTransform.X, translateTransform.Y);

            // Round coordinates to avoid blured window
            return position.Round();
        }

        /// <summary>
        /// Captures the mouse cursor.
        /// </summary>
        private void CaptureMouseCursor()
        {
            contentRoot.CaptureMouse();
            isMouseCaptured = true;
        }

        /// <summary>
        /// Executed when mouse moves.
        /// </summary>
        /// <param name="e">The data for the event.</param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (windowState == WindowState.Normal && ResizeEnabled && windowAction == WindowAction.None)
            {
                Point mousePosition = e.GetPosition(contentRoot);

                if (IsMouseOverButtons(mousePosition, contentRoot))
                    this.Cursor = Cursors.Arrow;
                else
                    resizeController.SetCursor(mousePosition);
            }

            Point p = e.GetPosition(HostPanel);
            double dx = p.X - clickPoint.X;
            double dy = p.Y - clickPoint.Y;

            if (windowAction == WindowAction.Resize)
                resizeController.Resize(dx, dy);

            if (windowAction == WindowAction.Move)
            {
                Point point = clickWindowPosition.Add(dx, dy);
                Rect rect = new Rect(point.X, point.Y, ActualWidth, ActualHeight);

                point = snapinController.SnapRectangle(rect);
                MoveWindow(point);

                inertiaController.MoveToPoint(Position);
            }
        }

        /// <summary>
        /// Determines whether the mouse is over buttons in the the specified mouse position.
        /// </summary>
        /// <param name="position">The mouse position.</param>
        /// <param name="origin">Relative origin.</param>
        /// <returns><c>true</c> if mouse is mouse over buttons.</returns>
        private bool IsMouseOverButtons(Point position, UIElement origin)
        {
            return (minimizeButton.IsVisible() && minimizeButton.ContainsPoint(position, origin)) ||
                   (maximizeButton.IsVisible() && maximizeButton.ContainsPoint(position, origin)) ||
                   (restoreButton.IsVisible() && restoreButton.ContainsPoint(position, origin)) ||
                   (closeButton.IsVisible() && closeButton.ContainsPoint(position, origin));
        }

        /// <summary>
        /// Moves the window to the specified coordinates.
        /// </summary>
        /// <param name="point">Coordinates of the window.</param>
        private void MoveWindow(Point point)
        {
            if (contentRoot != null && !point.IsNotSet())
            {
                // Round coordinates to avoid blured window
                double x = Math.Round(Math.Max(0, point.X));
                double y = Math.Round(Math.Max(0, point.Y));

                var transformGroup = contentRoot.RenderTransform as TransformGroup;
                var translateTransform = transformGroup.Children.OfType<TranslateTransform>().FirstOrDefault();
                if (translateTransform == null)
                {
                    transformGroup.Children.Add(new TranslateTransform() { X = x, Y = y });
                }
                else
                {
                    translateTransform.X = x;
                    translateTransform.Y = y;
                }

                Point newPosition = new Point(x, y);

                if (Position != newPosition)
                    Position = newPosition;
            }
        }

        /// <summary>
        /// Saves current size and position of the window in the IsolatedStorage.
        /// The key of the settings is the Tag of the window (if not null).
        /// </summary>
        private void SaveSizeAndPosition()
        {
            if (IsWindowTagSet)
            {
                string positionKey = GetAppSettingsKey("Position");
                string sizeKey = GetAppSettingsKey("Size");

                Point point = windowState == WindowState.Normal ? Position : previousPosition;
                localStorage[positionKey] = point;

                Size size = windowState == WindowState.Normal ? new Size(ActualWidth, ActualHeight) : previousSize;
                localStorage[sizeKey] = size;
            }
        }

        /// <summary>
        /// Gets the application settings key used to store properties in the IsolatedStorage.
        /// </summary>
        /// <param name="key">The key of the property, e.g. "Position".</param>
        /// <returns>Combined settings key or empty string.</returns>
        private string GetAppSettingsKey(string key)
        {
            string tag = this.Tag as string;
            return tag + ":" + key;
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
        }
    }
}