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.
268 lines
11 KiB
268 lines
11 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.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 Focus Management
|
|
static List<DockingManager> _managers = new List<DockingManager>();
|
|
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;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static FullWeakDictionary<ILayoutElement, IInputElement> _modelFocusedElement = new FullWeakDictionary<ILayoutElement, IInputElement>();
|
|
static WeakDictionary<ILayoutElement, IntPtr> _modelFocusedWindowHandle = new WeakDictionary<ILayoutElement, IntPtr>();
|
|
|
|
/// <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;
|
|
}
|
|
static WeakReference _lastFocusedElement;
|
|
|
|
/// <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);
|
|
}
|
|
|
|
}
|
|
|
|
static WindowHookHandler _windowHandler = null;
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static DispatcherOperation _setFocusAsyncOperation;
|
|
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
static WeakReference _lastFocusedElementBeforeEnterMenuMode = null;
|
|
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);
|
|
}
|
|
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
|
|
|
|
}
|
|
}
|
|
|