/************************************************************************************* Extended WPF Toolkit Copyright (C) 2007-2013 Xceed Software Inc. This program is provided to you under the terms of the Microsoft Public License (Ms-PL) as published at http://wpftoolkit.codeplex.com/license For more features, controls, and fast professional support, pick up the Plus Edition at http://xceed.com/wpf_toolkit Stay informed: follow @datagrid on Twitter or Like http://facebook.com/datagrids ***********************************************************************************/ /**************************************************************************\ Copyright Microsoft Corporation. All Rights Reserved. \**************************************************************************/ namespace Microsoft.Windows.Shell { using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Windows; using System.Windows.Data; using Standard; public class WindowChrome : Freezable { private struct _SystemParameterBoundProperty { public string SystemParameterPropertyName { get; set; } public DependencyProperty DependencyProperty { get; set; } } // Named property available for fully extending the glass frame. public static Thickness GlassFrameCompleteThickness { get { return new Thickness( -1 ); } } #region Attached Properties public static readonly DependencyProperty WindowChromeProperty = DependencyProperty.RegisterAttached( "WindowChrome", typeof( WindowChrome ), typeof( WindowChrome ), new PropertyMetadata( null, _OnChromeChanged ) ); private static void _OnChromeChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) { // The different design tools handle drawing outside their custom window objects differently. // Rather than try to support this concept in the design surface let the designer draw its own // chrome anyways. // There's certainly room for improvement here. if( System.ComponentModel.DesignerProperties.GetIsInDesignMode( d ) ) { return; } var window = ( Window )d; var newChrome = ( WindowChrome )e.NewValue; Assert.IsNotNull( window ); // Update the ChromeWorker with this new object. // If there isn't currently a worker associated with the Window then assign a new one. // There can be a many:1 relationship of to Window to WindowChrome objects, but a 1:1 for a Window and a WindowChromeWorker. WindowChromeWorker chromeWorker = WindowChromeWorker.GetWindowChromeWorker( window ); if( chromeWorker == null ) { chromeWorker = new WindowChromeWorker(); WindowChromeWorker.SetWindowChromeWorker( window, chromeWorker ); } chromeWorker.SetWindowChrome( newChrome ); } [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0" )] [SuppressMessage( "Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters" )] public static WindowChrome GetWindowChrome( Window window ) { Verify.IsNotNull( window, "window" ); return ( WindowChrome )window.GetValue( WindowChromeProperty ); } [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0" )] [SuppressMessage( "Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters" )] public static void SetWindowChrome( Window window, WindowChrome chrome ) { Verify.IsNotNull( window, "window" ); window.SetValue( WindowChromeProperty, chrome ); } public static readonly DependencyProperty IsHitTestVisibleInChromeProperty = DependencyProperty.RegisterAttached( "IsHitTestVisibleInChrome", typeof( bool ), typeof( WindowChrome ), new FrameworkPropertyMetadata( false, FrameworkPropertyMetadataOptions.Inherits ) ); [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0" )] [SuppressMessage( "Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters" )] public static bool GetIsHitTestVisibleInChrome( IInputElement inputElement ) { Verify.IsNotNull( inputElement, "inputElement" ); var dobj = inputElement as DependencyObject; if( dobj == null ) { throw new ArgumentException( "The element must be a DependencyObject", "inputElement" ); } return ( bool )dobj.GetValue( IsHitTestVisibleInChromeProperty ); } [SuppressMessage( "Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "0" )] [SuppressMessage( "Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters" )] public static void SetIsHitTestVisibleInChrome( IInputElement inputElement, bool hitTestVisible ) { Verify.IsNotNull( inputElement, "inputElement" ); var dobj = inputElement as DependencyObject; if( dobj == null ) { throw new ArgumentException( "The element must be a DependencyObject", "inputElement" ); } dobj.SetValue( IsHitTestVisibleInChromeProperty, hitTestVisible ); } #endregion #region Dependency Properties public static readonly DependencyProperty CaptionHeightProperty = DependencyProperty.Register( "CaptionHeight", typeof( double ), typeof( WindowChrome ), new PropertyMetadata( 0d, ( d, e ) => ( ( WindowChrome )d )._OnPropertyChangedThatRequiresRepaint() ), value => ( double )value >= 0d ); /// The extent of the top of the window to treat as the caption. public double CaptionHeight { get { return ( double )GetValue( CaptionHeightProperty ); } set { SetValue( CaptionHeightProperty, value ); } } public static readonly DependencyProperty ResizeBorderThicknessProperty = DependencyProperty.Register( "ResizeBorderThickness", typeof( Thickness ), typeof( WindowChrome ), new PropertyMetadata( default( Thickness ) ), ( value ) => Utility.IsThicknessNonNegative( ( Thickness )value ) ); public Thickness ResizeBorderThickness { get { return ( Thickness )GetValue( ResizeBorderThicknessProperty ); } set { SetValue( ResizeBorderThicknessProperty, value ); } } public static readonly DependencyProperty GlassFrameThicknessProperty = DependencyProperty.Register( "GlassFrameThickness", typeof( Thickness ), typeof( WindowChrome ), new PropertyMetadata( default( Thickness ), ( d, e ) => ( ( WindowChrome )d )._OnPropertyChangedThatRequiresRepaint(), ( d, o ) => _CoerceGlassFrameThickness( ( Thickness )o ) ) ); private static object _CoerceGlassFrameThickness( Thickness thickness ) { // If it's explicitly set, but set to a thickness with at least one negative side then // coerce the value to the stock GlassFrameCompleteThickness. if( !Utility.IsThicknessNonNegative( thickness ) ) { return GlassFrameCompleteThickness; } return thickness; } public Thickness GlassFrameThickness { get { return ( Thickness )GetValue( GlassFrameThicknessProperty ); } set { SetValue( GlassFrameThicknessProperty, value ); } } public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( "CornerRadius", typeof( CornerRadius ), typeof( WindowChrome ), new PropertyMetadata( default( CornerRadius ), ( d, e ) => ( ( WindowChrome )d )._OnPropertyChangedThatRequiresRepaint() ), ( value ) => Utility.IsCornerRadiusValid( ( CornerRadius )value ) ); public CornerRadius CornerRadius { get { return ( CornerRadius )GetValue( CornerRadiusProperty ); } set { SetValue( CornerRadiusProperty, value ); } } #region ShowSystemMenu /// /// Gets or sets the ShowSystemMenu property. This dependency property /// indicates if the system menu should be shown at right click on the caption. /// public bool ShowSystemMenu { get; set; } #endregion #endregion protected override Freezable CreateInstanceCore() { return new WindowChrome(); } private static readonly List<_SystemParameterBoundProperty> _BoundProperties = new List<_SystemParameterBoundProperty> { new _SystemParameterBoundProperty { DependencyProperty = CornerRadiusProperty, SystemParameterPropertyName = "WindowCornerRadius" }, new _SystemParameterBoundProperty { DependencyProperty = CaptionHeightProperty, SystemParameterPropertyName = "WindowCaptionHeight" }, new _SystemParameterBoundProperty { DependencyProperty = ResizeBorderThicknessProperty, SystemParameterPropertyName = "WindowResizeBorderThickness" }, new _SystemParameterBoundProperty { DependencyProperty = GlassFrameThicknessProperty, SystemParameterPropertyName = "WindowNonClientFrameThickness" }, }; public WindowChrome() { // Effective default values for some of these properties are set to be bindings // that set them to system defaults. // A more correct way to do this would be to Coerce the value iff the source of the DP was the default value. // Unfortunately with the current property system we can't detect whether the value being applied at the time // of the coersion is the default. foreach( var bp in _BoundProperties ) { // This list must be declared after the DP's are assigned. Assert.IsNotNull( bp.DependencyProperty ); BindingOperations.SetBinding( this, bp.DependencyProperty, new Binding { Source = SystemParameters2.Current, Path = new PropertyPath( bp.SystemParameterPropertyName ), Mode = BindingMode.OneWay, UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged, } ); } } private void _OnPropertyChangedThatRequiresRepaint() { var handler = PropertyChangedThatRequiresRepaint; if( handler != null ) { handler( this, EventArgs.Empty ); } } internal event EventHandler PropertyChangedThatRequiresRepaint; } }