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.

272 lines
9.7 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.Windows.Input;
using System.Windows.Interop;
using System.Windows;
using System.Diagnostics;
using Xceed.Wpf.AvalonDock.Layout;
using System.Windows.Media;
using System.Windows.Threading;
namespace Xceed.Wpf.AvalonDock.Controls
{
internal static class FocusElementManager
{
#region Member
private static List<DockingManager> _managers = new List<DockingManager>();
private static FullWeakDictionary<ILayoutElement, IInputElement> _modelFocusedElement = new FullWeakDictionary<ILayoutElement, IInputElement>();
private static WeakDictionary<ILayoutElement, IntPtr> _modelFocusedWindowHandle = new WeakDictionary<ILayoutElement, IntPtr>();
private static WeakReference _lastFocusedElement;
private static WindowHookHandler _windowHandler = null;
private static DispatcherOperation _setFocusAsyncOperation;
private static WeakReference _lastFocusedElementBeforeEnterMenuMode = null;
#endregion
#region Internal Methods
internal static void SetupFocusManagement( DockingManager manager )
{
if( _managers.Count == 0 )
{
//InputManager.Current.EnterMenuMode += new EventHandler(InputManager_EnterMenuMode);
//InputManager.Current.LeaveMenuMode += new EventHandler(InputManager_LeaveMenuMode);
_windowHandler = new WindowHookHandler();
_windowHandler.FocusChanged += new EventHandler<FocusChangeEventArgs>( WindowFocusChanging );
//_windowHandler.Activate += new EventHandler<WindowActivateEventArgs>(WindowActivating);
_windowHandler.Attach();
if( Application.Current != null )
Application.Current.Exit += new ExitEventHandler( Current_Exit );
}
manager.PreviewGotKeyboardFocus += new KeyboardFocusChangedEventHandler( manager_PreviewGotKeyboardFocus );
_managers.Add( manager );
}
internal static void FinalizeFocusManagement( DockingManager manager )
{
manager.PreviewGotKeyboardFocus -= new KeyboardFocusChangedEventHandler( manager_PreviewGotKeyboardFocus );
_managers.Remove( manager );
if( _managers.Count == 0 )
{
//InputManager.Current.EnterMenuMode -= new EventHandler(InputManager_EnterMenuMode);
//InputManager.Current.LeaveMenuMode -= new EventHandler(InputManager_LeaveMenuMode);
if( _windowHandler != null )
{
_windowHandler.FocusChanged -= new EventHandler<FocusChangeEventArgs>( WindowFocusChanging );
//_windowHandler.Activate -= new EventHandler<WindowActivateEventArgs>(WindowActivating);
_windowHandler.Detach();
_windowHandler = null;
}
}
}
/// <summary>
/// Get the input element that was focused before user left the layout element
/// </summary>
/// <param name="model">Element to look for</param>
/// <returns>Input element </returns>
internal static IInputElement GetLastFocusedElement( ILayoutElement model )
{
IInputElement objectWithFocus;
if( _modelFocusedElement.GetValue( model, out objectWithFocus ) )
return objectWithFocus;
return null;
}
/// <summary>
/// Get the last window handle focused before user left the element passed as argument
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
internal static IntPtr GetLastWindowHandle( ILayoutElement model )
{
IntPtr handleWithFocus;
if( _modelFocusedWindowHandle.GetValue( model, out handleWithFocus ) )
return handleWithFocus;
return IntPtr.Zero;
}
/// <summary>
/// Given a layout element tries to set the focus of the keyword where it was before user moved to another element
/// </summary>
/// <param name="model"></param>
internal static void SetFocusOnLastElement( ILayoutElement model )
{
bool focused = false;
IInputElement objectToFocus;
if( _modelFocusedElement.GetValue( model, out objectToFocus ) )
{
focused = objectToFocus == Keyboard.Focus( objectToFocus );
}
IntPtr handleToFocus;
if( _modelFocusedWindowHandle.GetValue( model, out handleToFocus ) )
focused = IntPtr.Zero != Win32Helper.SetFocus( handleToFocus );
if( focused )
{
_lastFocusedElement = new WeakReference( model );
}
}
#endregion
#region Private Methods
private static void Current_Exit( object sender, ExitEventArgs e )
{
Application.Current.Exit -= new ExitEventHandler( Current_Exit );
if( _windowHandler != null )
{
_windowHandler.FocusChanged -= new EventHandler<FocusChangeEventArgs>( WindowFocusChanging );
//_windowHandler.Activate -= new EventHandler<WindowActivateEventArgs>(WindowActivating);
_windowHandler.Detach();
_windowHandler = null;
}
}
private static void manager_PreviewGotKeyboardFocus( object sender, KeyboardFocusChangedEventArgs e )
{
var focusedElement = e.NewFocus as Visual;
if( focusedElement != null &&
!( focusedElement is LayoutAnchorableTabItem || focusedElement is LayoutDocumentTabItem ) )
//Avoid tracking focus for elements like this
{
var parentAnchorable = focusedElement.FindVisualAncestor<LayoutAnchorableControl>();
if( parentAnchorable != null )
{
_modelFocusedElement[ parentAnchorable.Model ] = e.NewFocus;
}
else
{
var parentDocument = focusedElement.FindVisualAncestor<LayoutDocumentControl>();
if( parentDocument != null )
{
_modelFocusedElement[ parentDocument.Model ] = e.NewFocus;
}
}
}
}
private static void WindowFocusChanging( object sender, FocusChangeEventArgs e )
{
foreach( var manager in _managers )
{
var hostContainingFocusedHandle = manager.FindLogicalChildren<HwndHost>().FirstOrDefault( hw => Win32Helper.IsChild( hw.Handle, e.GotFocusWinHandle ) );
if( hostContainingFocusedHandle != null )
{
var parentAnchorable = hostContainingFocusedHandle.FindVisualAncestor<LayoutAnchorableControl>();
if( parentAnchorable != null )
{
_modelFocusedWindowHandle[ parentAnchorable.Model ] = e.GotFocusWinHandle;
if( parentAnchorable.Model != null )
parentAnchorable.Model.IsActive = true;
}
else
{
var parentDocument = hostContainingFocusedHandle.FindVisualAncestor<LayoutDocumentControl>();
if( parentDocument != null )
{
_modelFocusedWindowHandle[ parentDocument.Model ] = e.GotFocusWinHandle;
if( parentDocument.Model != null )
parentDocument.Model.IsActive = true;
}
}
}
}
}
private static void WindowActivating( object sender, WindowActivateEventArgs e )
{
if( Keyboard.FocusedElement == null &&
_lastFocusedElement != null &&
_lastFocusedElement.IsAlive )
{
var elementToSetFocus = _lastFocusedElement.Target as ILayoutElement;
if( elementToSetFocus != null )
{
var manager = elementToSetFocus.Root.Manager;
if( manager == null )
return;
IntPtr parentHwnd;
if( !manager.GetParentWindowHandle( out parentHwnd ) )
return;
if( e.HwndActivating != parentHwnd )
return;
_setFocusAsyncOperation = Dispatcher.CurrentDispatcher.BeginInvoke( new Action( () =>
{
try
{
SetFocusOnLastElement( elementToSetFocus );
}
finally
{
_setFocusAsyncOperation = null;
}
} ), DispatcherPriority.Input );
}
}
}
private static void InputManager_EnterMenuMode( object sender, EventArgs e )
{
if( Keyboard.FocusedElement == null )
return;
var lastfocusDepObj = Keyboard.FocusedElement as DependencyObject;
if( lastfocusDepObj.FindLogicalAncestor<DockingManager>() == null )
{
_lastFocusedElementBeforeEnterMenuMode = null;
return;
}
_lastFocusedElementBeforeEnterMenuMode = new WeakReference( Keyboard.FocusedElement );
}
private static void InputManager_LeaveMenuMode( object sender, EventArgs e )
{
if( _lastFocusedElementBeforeEnterMenuMode != null &&
_lastFocusedElementBeforeEnterMenuMode.IsAlive )
{
var lastFocusedInputElement = _lastFocusedElementBeforeEnterMenuMode.GetValueOrDefault<UIElement>();
if( lastFocusedInputElement != null )
{
if( lastFocusedInputElement != Keyboard.Focus( lastFocusedInputElement ) )
Debug.WriteLine( "Unable to activate the element" );
}
}
}
#endregion
}
}