Click here to Skip to main content
15,893,668 members
Articles / Programming Languages / C#

FloatingWindow - Multi-windows Interface for Silverlight 4

Rate me:
Please Sign up or sign in to vote.
4.92/5 (80 votes)
16 May 2011CPOL8 min read 508K   3.9K   123  
Resizable windows simulating multi-windows desktop interface for Silverlight 4
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO.IsolatedStorage;
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 System.Windows.Media.Imaging;
using SilverFlow.Controls.Enums;

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_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)]
    public class FloatingWindow : ContentControl, IResizableElement, IDisposable
    {
        #region Constants

        // Template parts
        private const string PART_Chrome = "Chrome";
        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";

        // 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 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)
                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 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 FrameworkElement root;
        private FrameworkElement contentPresenter;
        private FrameworkElement contentRoot;
        private FrameworkElement chrome;
        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;

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

        // Specifies whether the window is moving or resizing
        private MouseAction mouseAction;

        // 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();
        }

        #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 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 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 Snapin controller.
        /// </summary>
        /// <value></value>
        public ISnapinController SnapinController
        {
            get { return snapinController; }
        }

        /// <summary>
        /// Gets the FloatingWindowHost containing the window.
        /// </summary>
        /// <value>FloatingWindowHost, containing the window.</value>
        private FloatingWindowHost Host
        {
            get { return this.Parent as FloatingWindowHost; }
        }

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

        /// <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((Host.ActualWidth - Width) / 2, (Host.ActualHeight - Height) / 2);
            }
        }

        #endregion Properties

        /// <summary>
        /// Opens a <see cref="FloatingWindow" /> and
        /// returns without waiting for the <see cref="FloatingWindow" /> to open.
        /// </summary>
        public void Show()
        {
            // Display the window in previously saved position
            Show(Position);
        }

        /// <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>
        /// 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 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>
        public void Show(Point point)
        {
            if (Host == null)
                throw new InvalidOperationException("The FloatingWindow was not added to the FloatingWindowHost.");

            if (!IsOpen)
            {
                if (IsModal)
                    Host.ShowOverlay();

                this.SetVisible(true);

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

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

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

                if (!WindowSizeIsSet)
                {
                    contentPresenter.LayoutUpdated += (s, e) =>
                        {
                            // If window size is not set explicitly we should wait
                            // when the window layout is updated to get its real size
                            Width = ActualWidth;
                            Height = ActualHeight;

                            if (point.IsNotSet())
                            {
                                IsOpen = true;
                                point = CenteredWindowPosition;
                                MoveWindow(point);
                            }
                        };
                }

                if (point.IsNotSet() && WindowSizeIsSet)
                {
                    IsOpen = true;
                    point = CenteredWindowPosition;
                    MoveWindow(point);
                    VisualStateManager.GoToState(this, VSMSTATE_StateOpen, true);
                }
                else
                {
                    MoveWindow(point);
                    VisualStateManager.GoToState(this, VSMSTATE_StateOpen, true);
                }
            }
            else
            {
                MoveWindow(point);
            }
        }

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

                    SetClippingRegion();
                    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();
            Host.UpdateIconbar();
        }

        /// <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 (Host != null)
            {
                Host.SetTopmostWindow(this);
            }
        }

        /// <summary>
        /// Ensures the window is visible.
        /// </summary>
        private void EnsureVisible()
        {
            if (Host != null && (Position.X >= Host.ActualWidth || Position.Y >= Host.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()
        {
            CancelEventArgs e = new CancelEventArgs();
            OnClosing(e);

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

                if (IsModal)
                    Host.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()
        {
            string positionKey = GetAppSettingsKey("Position");
            string sizeKey = GetAppSettingsKey("Size");

            if (!string.IsNullOrEmpty(positionKey) && !string.IsNullOrEmpty(sizeKey))
            {
                if (IsolatedStorageSettings.ApplicationSettings.Contains(positionKey))
                {
                    Position = (Point)IsolatedStorageSettings.ApplicationSettings[positionKey];
                }

                if (IsolatedStorageSettings.ApplicationSettings.Contains(sizeKey))
                {
                    Size size = (Size)IsolatedStorageSettings.ApplicationSettings[sizeKey];
                    if (!size.IsEmpty && !size.IsNotSet())
                    {
                        Width = size.Width;
                        Height = 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;
            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.");

            GetStoryboards();
            InitializeContentRootTransformGroup();

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

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

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

            SubscribeToTemplatePartEvents();
            SubscribeToStoryBoardEvents();
        }

        /// <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();
                    }
                }
            }
        }

        /// <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>
        /// Sets the clipping region for the <see cref="FloatingWindow" /> window.
        /// </summary>
        private void SetClippingRegion()
        {
            if (Host != null)
            {
                RectangleGeometry rg = new RectangleGeometry();
                rg.Rect = new Rect(0, 0, Host.ActualWidth, Host.ActualHeight);
                root.Clip = rg;
            }
        }

        /// <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)
        {
            EventHandler handler = Closed;
            if (handler != null)
            {
                handler(this, e);
            }

            FloatingWindowHost host = Host; 
            host.Remove(this);
            host.UpdateIconbar();
            host.ActivateTopmostWindow();

            UnsubscribeFromStoryBoardEvents();
            SaveSizeAndPosition();
            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();
            }

            Host.UpdateIconbar();
        }

        /// <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);

            IsOpen = true;
            OnOpened();
        }

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

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

            // Attach MouseLeftButtonDownEvent 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();
                }
            }
        }

        /// <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.Host != null && Application.Current.Host.Content != null)
                Application.Current.Exit -= new EventHandler(Application_Exit);

            if (Host != null)
            {
                Host.SizeChanged -= new SizeChangedEventHandler(Host_SizeChanged);
                Host.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);
        }

        /// <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);
        }

        /// <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(Width, Height);
                }

                minimizedWindowThumbnail = GetThumbnailImage();

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

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

            Host.UpdateIconbar();
            Host.ActivateTopmostWindow();
        }

        /// <summary>
        /// Creates thumbnail image 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;

            int width = icon.Width.IsNotSet() ? (int)icon.ActualWidth : (int)icon.Width;
            int height = icon.Height.IsNotSet() ? (int)icon.ActualHeight : (int)icon.Height;

            ScaleTransform transform = null;

            // If the Icon is an image - do not scale it
            if (!(Icon is Image))
            {
                // Scale down the Icon presented by the FrameworkElement to fit it into the window's thumbnail
                double scaleX = Host.IconWidth / width;
                double scaleY = Host.IconHeight / height;
                double minScale = Math.Min(scaleX, scaleY);

                if (minScale < 1)
                {
                    transform = new ScaleTransform
                    {
                        ScaleX = minScale,
                        ScaleY = minScale
                    };

                    width = (int)(width * minScale);
                    height = (int)(height * minScale);
                }
            }

            WriteableBitmap bitmap = new WriteableBitmap(width, height);
            bitmap.Render(icon, transform);
            bitmap.Invalidate();

            return bitmap;
        }

        /// <summary>
        /// Maximizes the window.
        /// </summary>
        private void MaximizeWindow()
        {
            if (windowState != WindowState.Maximized)
            {
                if (maximizeButton != null && restoreButton != null && Host != null)
                {
                    maximizeButton.SetVisible(false);
                    restoreButton.SetVisible(true);
                    VisualStateManager.GoToState(restoreButton, VSMSTATE_StateNormal, true);

                    // Store previous coordinates
                    previousPosition = Position;
                    previousSize = new Size(Width, Height);

                    // 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>
        /// Starts maximizing animation.
        /// </summary>
        private void StartMaximizingAnimation()
        {
            this.MoveAndResize(new Point(0, 0), Host.ActualWidth, Host.ActualHeight, 
                MaximizingDurationInMilliseconds, Maximizing_Completed);
        }

        /// <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 && Host != null)
                {
                    restoreButton.SetVisible(false);
                    maximizeButton.SetVisible(true);
                    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()
        {
            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)
        {
            SetClippingRegion();

            if (windowState == WindowState.Maximized)
            {
                Width = Host.ActualWidth;
                Height = double.IsInfinity(MaxHeight) ? Host.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)
            {
                clickPoint = e.GetPosition(Host);
                clickWindowPosition = Position;
                snapinController.SnapinDistance = Host.SnapinDistance;
                snapinController.SnapinMargin = Host.SnapinMargin;
                snapinController.SnapinEnabled = Host.SnapinEnabled;

                if (ResizeEnabled && resizeController.CanResize)
                {
                    snapinController.SnapinBounds = Host.GetSnapinBounds(this);
                    resizeController.StartResizing();
                    CaptureMouseCursor();
                    mouseAction = MouseAction.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 = Host.GetSnapinBounds(this);
                        CaptureMouseCursor();
                        mouseAction = MouseAction.Move;
                    }
                }
            }
        }

        /// <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 (isMouseCaptured)
            {
                contentRoot.ReleaseMouseCapture();
                isMouseCaptured = false;
            }

            mouseAction = MouseAction.None;
        }

        /// <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 && mouseAction == MouseAction.None)
            {
                resizeController.SetCursor(e.GetPosition(contentRoot));
            }

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

            if (mouseAction == MouseAction.Resize)
            {
                resizeController.Resize(dx, dy);
            }

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

                point = snapinController.SnapRectangle(rect);

                MoveWindow(point);
            }
        }

        /// <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;
                }

                Position = new Point(x, y);
            }
        }

        /// <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()
        {
            string positionKey = GetAppSettingsKey("Position");
            string sizeKey = GetAppSettingsKey("Size");

            if (!string.IsNullOrEmpty(positionKey) && !string.IsNullOrEmpty(sizeKey))
            {
                Point point = windowState == WindowState.Normal ? Position : previousPosition;
                IsolatedStorageSettings.ApplicationSettings[positionKey] = point;

                Size size = windowState == WindowState.Normal ? new Size(Width, Height) : previousSize;
                IsolatedStorageSettings.ApplicationSettings[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 appSettingsKey = string.Empty;
            string tag = this.Tag as string;

            if (!string.IsNullOrWhiteSpace(tag) && !string.IsNullOrWhiteSpace(key))
            {
                appSettingsKey = tag + ":" + key;
            }

            return appSettingsKey;
        }

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

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 Code Project Open License (CPOL)


Written By
Latvia Latvia
Jevgenij lives in Riga, Latvia. He started his programmer's career in 1983 developing software for radio equipment CAD systems. Created computer graphics for TV. Developed Internet credit card processing systems for banks.
Now he is System Analyst in Accenture.

Comments and Discussions