| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273 |
- /*************************************************************************************
- 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);
- Trace.WriteLine( string.Format( "SetFocusOnLastElement(focused={0}, model={1}, element={2})", focused, model, handleToFocus == IntPtr.Zero ? ( objectToFocus == null ? "" : objectToFocus.ToString() ) : handleToFocus.ToString() ) );
- 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)
- {
- Trace.WriteLine("WindowActivating");
- 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.Background);
- }
- }
- }
- 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
- }
- }
|