All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

449 lines
15 KiB

/*************************************************************************************
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
***********************************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows;
using System.ComponentModel;
using System.Windows.Input;
using System.Windows.Controls.Primitives;
using System.Windows.Media;
using Xceed.Wpf.Toolkit.Core;
namespace Xceed.Wpf.Toolkit.Primitives
{
public class WindowContainer : Canvas
{
#region Constructors
static WindowContainer()
{
// The default background must be transparent in order to be able to trap
// all mouse events when a modal window is displayed.
var defaultModalBackgroundBrush = new SolidColorBrush( Colors.Transparent );
defaultModalBackgroundBrush.Freeze();
ModalBackgroundBrushProperty = DependencyProperty.Register( "ModalBackgroundBrush", typeof( Brush ), typeof( WindowContainer ), new UIPropertyMetadata( defaultModalBackgroundBrush, OnModalBackgroundBrushChanged ) );
}
public WindowContainer()
{
this.SizeChanged += new SizeChangedEventHandler( this.WindowContainer_SizeChanged );
this.LayoutUpdated += new EventHandler( this.WindowContainer_LayoutUpdated );
this.Loaded += new RoutedEventHandler( WindowContainer_Loaded );
this.ClipToBounds = true;
}
void WindowContainer_Loaded( object sender, RoutedEventArgs e )
{
foreach( WindowControl window in this.Children )
{
window.SetIsActiveInternal( false );
}
this.SetNextActiveWindow( null );
}
#endregion //Constructors
#region Members
private Brush _defaultBackgroundBrush;
private bool _isModalBackgroundApplied;
#endregion
#region Properties
#region ModalBackgroundBrush
/// <summary>
/// Identifies the ModalBackgroundBrush dependency property.
/// </summary>
// Initialized in the static constructor.
public static readonly DependencyProperty ModalBackgroundBrushProperty;
/// <summary>
/// When using a modal window in the WindowContainer, a ModalBackgroundBrush can be set
/// for the WindowContainer.
/// </summary>
public Brush ModalBackgroundBrush
{
get
{
return ( Brush )GetValue( ModalBackgroundBrushProperty );
}
set
{
SetValue( ModalBackgroundBrushProperty, value );
}
}
private static void OnModalBackgroundBrushChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
{
WindowContainer windowContainer = ( WindowContainer )d;
if( windowContainer != null )
windowContainer.OnModalBackgroundBrushChanged( ( Brush )e.OldValue, ( Brush )e.NewValue );
}
protected virtual void OnModalBackgroundBrushChanged( Brush oldValue, Brush newValue )
{
this.SetModalBackground();
}
#endregion //ModalBackgroundBrush
#endregion
#region Base Class Override
/// <summary>
/// Measure the size of the WindowContainer based on its children.
/// </summary>
protected override Size MeasureOverride( Size constraint )
{
Size size = base.MeasureOverride( constraint );
if( this.Children.Count > 0 )
{
double width = double.IsNaN( this.Width )
? this.Children.OfType<WindowControl>().Max( ( w ) => w.Left + w.DesiredSize.Width )
: this.Width;
double height = double.IsNaN( this.Height )
? this.Children.OfType<WindowControl>().Max( ( w ) => w.Top + w.DesiredSize.Height )
: this.Height;
return new Size( Math.Min( width, constraint.Width), Math.Min( height, constraint.Height) );
}
return size;
}
/// <summary>
/// Register and unregister to children events.
/// </summary>
protected override void OnVisualChildrenChanged( DependencyObject visualAdded, DependencyObject visualRemoved )
{
base.OnVisualChildrenChanged( visualAdded, visualRemoved );
if( visualAdded != null && !( visualAdded is WindowControl ) )
throw new InvalidOperationException( "WindowContainer can only contain WindowControl types." );
if( visualRemoved != null )
{
WindowControl removedChild = ( WindowControl )visualRemoved;
removedChild.LeftChanged -= new EventHandler<EventArgs>( this.Child_LeftChanged );
removedChild.TopChanged -= new EventHandler<EventArgs>( this.Child_TopChanged );
removedChild.PreviewMouseLeftButtonDown -= new MouseButtonEventHandler( this.Child_PreviewMouseLeftButtonDown );
removedChild.IsVisibleChanged -= new DependencyPropertyChangedEventHandler( this.Child_IsVisibleChanged );
removedChild.IsKeyboardFocusWithinChanged -= new DependencyPropertyChangedEventHandler( this.Child_IsKeyboardFocusWithinChanged );
if( removedChild is ChildWindow )
{
( ( ChildWindow )removedChild ).IsModalChanged -= new EventHandler<EventArgs>( this.Child_IsModalChanged );
}
}
if( visualAdded != null )
{
WindowControl addedChild = ( WindowControl )visualAdded;
addedChild.LeftChanged += new EventHandler<EventArgs>( this.Child_LeftChanged );
addedChild.TopChanged += new EventHandler<EventArgs>( this.Child_TopChanged );
addedChild.PreviewMouseLeftButtonDown += new MouseButtonEventHandler( this.Child_PreviewMouseLeftButtonDown );
addedChild.IsVisibleChanged += new DependencyPropertyChangedEventHandler( this.Child_IsVisibleChanged );
addedChild.IsKeyboardFocusWithinChanged += new DependencyPropertyChangedEventHandler( this.Child_IsKeyboardFocusWithinChanged );
if( addedChild is ChildWindow )
{
( ( ChildWindow )addedChild ).IsModalChanged += new EventHandler<EventArgs>( this.Child_IsModalChanged );
}
}
}
#endregion
#region Event Handler
private void Child_LeftChanged( object sender, EventArgs e )
{
WindowControl windowControl = ( WindowControl )sender;
if( windowControl != null )
{
windowControl.Left = this.GetRestrictedLeft( windowControl );
}
Canvas.SetLeft( windowControl, windowControl.Left );
}
private void Child_TopChanged( object sender, EventArgs e )
{
WindowControl windowControl = ( WindowControl )sender;
if( windowControl != null )
{
windowControl.Top = this.GetRestrictedTop( windowControl );
}
Canvas.SetTop( windowControl, windowControl.Top );
}
private void Child_PreviewMouseLeftButtonDown( object sender, RoutedEventArgs e )
{
WindowControl windowControl = ( WindowControl )sender;
WindowControl modalWindow = this.GetModalWindow();
if( modalWindow == null )
{
this.SetNextActiveWindow( windowControl );
}
}
private void Child_IsModalChanged( object sender, EventArgs e )
{
this.SetModalBackground();
}
private void Child_IsVisibleChanged( object sender, DependencyPropertyChangedEventArgs e )
{
WindowControl windowControl = ( WindowControl )sender;
//Do not give access to data behind the WindowContainer as long as any child of WindowContainer is visible.
WindowControl firstVisibleChild = this.Children.OfType<WindowControl>().FirstOrDefault( ( x ) => x.Visibility == Visibility.Visible );
this.IsHitTestVisible = ( firstVisibleChild != null );
if( ( bool )e.NewValue )
{
this.SetChildPos( windowControl );
this.SetNextActiveWindow( windowControl );
}
else
{
this.SetNextActiveWindow( null );
}
WindowControl modalWindow = this.GetModalWindow();
foreach( WindowControl window in this.Children )
{
window.IsBlockMouseInputsPanelActive = ( modalWindow != null ) && !object.Equals( modalWindow, window );
}
this.SetModalBackground();
}
private void Child_IsKeyboardFocusWithinChanged( object sender, DependencyPropertyChangedEventArgs e )
{
WindowControl windowControl = ( WindowControl )sender;
if( ( bool )e.NewValue )
{
this.SetNextActiveWindow( windowControl );
}
}
private void WindowContainer_LayoutUpdated( object sender, EventArgs e )
{
foreach( WindowControl windowControl in this.Children )
{
//we only want to set the start position if this is the first time the control has bee initialized
if( !windowControl.IsStartupPositionInitialized && ( windowControl.ActualWidth != 0 ) && ( windowControl.ActualHeight != 0 ) )
{
this.SetChildPos( windowControl );
windowControl.IsStartupPositionInitialized = true;
}
}
}
private void WindowContainer_SizeChanged( object sender, SizeChangedEventArgs e )
{
foreach( WindowControl windowControl in this.Children )
{
//reposition our windows
windowControl.Left = this.GetRestrictedLeft( windowControl );
windowControl.Top = this.GetRestrictedTop( windowControl );
}
}
private void ExpandWindowControl( WindowControl windowControl )
{
if( windowControl != null )
{
windowControl.Left = 0;
windowControl.Top = 0;
windowControl.Width = Math.Min( this.ActualWidth, windowControl.MaxWidth );
windowControl.Height = Math.Min( this.ActualHeight, windowControl.MaxHeight );
}
}
#endregion
#region Private Methods
private void SetChildPos( WindowControl windowControl )
{
// A MessageBox with no X and Y will be centered.
// A ChildWindow with WindowStartupLocation == Center will be centered.
if( ( ( windowControl is MessageBox ) && ( windowControl.Left == 0 ) && ( windowControl.Top == 0 ) )
|| ( ( windowControl is ChildWindow ) && ( ( ( ChildWindow )windowControl ).WindowStartupLocation == WindowStartupLocation.Center ) ) )
{
this.CenterChild( windowControl );
}
else
{
Canvas.SetLeft( windowControl, windowControl.Left );
Canvas.SetTop( windowControl, windowControl.Top );
}
}
private void CenterChild( WindowControl windowControl )
{
if( ( windowControl.ActualWidth != 0 ) && ( windowControl.ActualHeight != 0 ) )
{
windowControl.Left = ( this.ActualWidth - windowControl.ActualWidth ) / 2.0;
windowControl.Left += (windowControl.Margin.Left - windowControl.Margin.Right);
windowControl.Top = ( this.ActualHeight - windowControl.ActualHeight ) / 2.0;
windowControl.Top += ( windowControl.Margin.Top - windowControl.Margin.Bottom );
}
}
private void SetNextActiveWindow( WindowControl windowControl )
{
if( !this.IsLoaded )
return;
if( this.IsModalWindow( windowControl ) )
{
this.BringToFront( windowControl );
}
else
{
WindowControl modalWindow = this.GetModalWindow();
// Modal window is always in front
if( modalWindow != null )
{
this.BringToFront( modalWindow );
}
else if( windowControl != null )
{
this.BringToFront( windowControl );
}
else
{
this.BringToFront( this.Children.OfType<WindowControl>()
.OrderByDescending( ( x ) => Canvas.GetZIndex( x ) )
.FirstOrDefault( ( x ) => x.Visibility == Visibility.Visible ) );
}
}
}
private void BringToFront( WindowControl windowControl )
{
if( windowControl != null )
{
int maxZIndez = this.Children.OfType<WindowControl>().Max( ( x ) => Canvas.GetZIndex( x ) );
Canvas.SetZIndex( windowControl, maxZIndez + 1 );
this.SetActiveWindow( windowControl );
}
}
private void SetActiveWindow( WindowControl windowControl )
{
if( windowControl.IsActive )
return;
foreach( WindowControl window in this.Children )
{
window.SetIsActiveInternal( false );
}
windowControl.SetIsActiveInternal( true );
}
private bool IsModalWindow( WindowControl windowControl )
{
return ( ( ( windowControl is MessageBox ) && (windowControl.Visibility == Visibility.Visible) )
|| ( ( windowControl is ChildWindow ) && ( ( ChildWindow )windowControl ).IsModal && ( ( ChildWindow )windowControl).WindowState == WindowState.Open ) );
}
private WindowControl GetModalWindow()
{
return this.Children.OfType<WindowControl>()
.OrderByDescending( ( x ) => Canvas.GetZIndex( x ) )
.FirstOrDefault( ( x ) => IsModalWindow( x ) && (x.Visibility == Visibility.Visible) );
}
private double GetRestrictedLeft( WindowControl windowControl )
{
if( windowControl.Left < 0 )
return 0;
if( ( ( windowControl.Left + windowControl.ActualWidth ) > this.ActualWidth ) && ( this.ActualWidth != 0 ) )
{
double x = this.ActualWidth - windowControl.ActualWidth;
return x < 0 ? 0 : x;
}
return windowControl.Left;
}
private double GetRestrictedTop( WindowControl windowControl )
{
if( windowControl.Top < 0 )
return 0;
if( ( ( windowControl.Top + windowControl.ActualHeight ) > this.ActualHeight ) && ( this.ActualHeight != 0 ) )
{
double y = this.ActualHeight - windowControl.ActualHeight;
return y < 0 ? 0 : y;
}
return windowControl.Top;
}
private void SetModalBackground()
{
// We have a modal window and a ModalBackgroundBrush set.
if( ( this.GetModalWindow() != null ) && ( this.ModalBackgroundBrush != null ) )
{
if( !_isModalBackgroundApplied )
{
_defaultBackgroundBrush = this.Background;
_isModalBackgroundApplied = true;
}
this.Background = this.ModalBackgroundBrush;
}
else
{
if( _isModalBackgroundApplied )
{
this.Background = _defaultBackgroundBrush;
_defaultBackgroundBrush = null;
_isModalBackgroundApplied = false;
}
}
}
#endregion
}
}