diff --git a/src/Libraries/AvalonDock/ManagedContent.cs b/src/Libraries/AvalonDock/ManagedContent.cs index 03744eeb3d..32984502e9 100644 --- a/src/Libraries/AvalonDock/ManagedContent.cs +++ b/src/Libraries/AvalonDock/ManagedContent.cs @@ -435,11 +435,15 @@ namespace AvalonDock if (ContainerPane != null && Manager != null)// && Manager.ActiveContent != this) { ContainerPane.SelectedItem = this; - ContainerPane.Focus(); + FocusContent(); if (Manager != null) Manager.ActiveContent = this; } } + + protected virtual void FocusContent() + { + } bool _isActiveDocument = false; diff --git a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj index fd38e481d1..aec649fbfa 100644 --- a/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj +++ b/src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj @@ -1,4 +1,5 @@ - + + Debug AnyCPU @@ -145,6 +146,7 @@ + AddOpenWithEntryDialog.cs diff --git a/src/Main/Base/Project/Src/Gui/CustomFocusManager.cs b/src/Main/Base/Project/Src/Gui/CustomFocusManager.cs new file mode 100644 index 0000000000..8a2fdf6da4 --- /dev/null +++ b/src/Main/Base/Project/Src/Gui/CustomFocusManager.cs @@ -0,0 +1,91 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Windows; +using System.Windows.Input; + +using ICSharpCode.Core; + +namespace ICSharpCode.SharpDevelop.Gui +{ + /// + /// Custom focus scope implementation. + /// See http://www.codeproject.com/KB/WPF/EnhancedFocusScope.aspx for a description of the problems with the normal WPF FocusScope. + /// + public static class CustomFocusManager + { + // DP for attached behavior, toggles remembering on or off + public static readonly DependencyProperty RememberFocusedChildProperty = + DependencyProperty.RegisterAttached("RememberFocusedChild", typeof(bool), typeof(CustomFocusManager), + new FrameworkPropertyMetadata(false, OnRememberFocusedChildChanged)); + + // This property is used to remember the focused child. + // We are using WeakReferences because a visual tree may change while it is not visible, and we don't + // want to keep parts of the old visual tree alive. + static readonly DependencyProperty FocusedChildProperty = + DependencyProperty.RegisterAttached("FocusedChild", typeof(WeakReference), typeof(CustomFocusManager)); + + public static bool GetRememberFocusedChild(UIElement element) + { + if (element == null) + throw new ArgumentNullException("element"); + return (bool)element.GetValue(RememberFocusedChildProperty); + } + + public static void SetRememberFocusedChild(UIElement element, bool value) + { + if (element == null) + throw new ArgumentNullException("element"); + element.SetValue(RememberFocusedChildProperty, value); + } + + public static IInputElement GetFocusedChild(UIElement element) + { + if (element == null) + throw new ArgumentNullException("element"); + WeakReference r = (WeakReference)element.GetValue(FocusedChildProperty); + if (r != null) + return (IInputElement)r.Target; + else + return null; + } + + public static void SetFocusToRememberedChild(UIElement element) + { + IInputElement focusedChild = GetFocusedChild(element); + LoggingService.Debug("Restoring focus for " + element + " to " + focusedChild); + if (focusedChild != null) + Keyboard.Focus(focusedChild); + } + + static void OnRememberFocusedChildChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + UIElement element = d as UIElement; + if (element != null) { + if ((bool)e.OldValue) + element.RemoveHandler(UIElement.GotFocusEvent, onGotFocusEventHandler); + if ((bool)e.NewValue) + element.AddHandler(UIElement.GotFocusEvent, onGotFocusEventHandler, true); + } + } + + static readonly RoutedEventHandler onGotFocusEventHandler = OnGotFocus; + + static void OnGotFocus(object sender, RoutedEventArgs e) + { + UIElement element = (UIElement)sender; + IInputElement focusedElement = e.OriginalSource as IInputElement; + WeakReference r = (WeakReference)element.GetValue(FocusedChildProperty); + if (r != null) { + r.Target = focusedElement; + } else { + element.SetValue(FocusedChildProperty, new WeakReference(focusedElement)); + } + } + } +} diff --git a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs index 6bf0152111..317b3f36b0 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonPadContent.cs @@ -31,6 +31,7 @@ namespace ICSharpCode.SharpDevelop.Gui this.descriptor = descriptor; this.layout = layout; + CustomFocusManager.SetRememberFocusedChild(this, true); this.Name = descriptor.Class.Replace('.', '_'); this.SetValueToExtension(TitleProperty, new StringParseExtension(descriptor.Title)); placeholder = new TextBlock { Text = this.Title }; @@ -40,6 +41,16 @@ namespace ICSharpCode.SharpDevelop.Gui placeholder.IsVisibleChanged += AvalonPadContent_IsVisibleChanged; } + protected override void FocusContent() + { + IInputElement activeChild = CustomFocusManager.GetFocusedChild(this); + if (activeChild != null) { + LoggingService.Debug("Will move focus to: " + activeChild); + Dispatcher.BeginInvoke(DispatcherPriority.Background, + new Action(delegate { Keyboard.Focus(activeChild); })); + } + } + public void ShowInDefaultPosition() { AnchorStyle style; diff --git a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs index b20c7a69ee..06be17afa9 100644 --- a/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs +++ b/src/Main/Base/Project/Src/Gui/Workbench/Layouts/AvalonWorkbenchWindow.cs @@ -15,6 +15,7 @@ using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Windows.Media.Imaging; +using System.Windows.Threading; using AvalonDock; using ICSharpCode.Core; @@ -33,6 +34,7 @@ namespace ICSharpCode.SharpDevelop.Gui if (dockLayout == null) throw new ArgumentNullException("dockLayout"); + CustomFocusManager.SetRememberFocusedChild(this, true); this.IsFloatingAllowed = true; this.dockLayout = dockLayout; viewContents = new ViewContentCollection(this); @@ -41,6 +43,16 @@ namespace ICSharpCode.SharpDevelop.Gui OnTitleNameChanged(this, EventArgs.Empty); } + protected override void FocusContent() + { + IInputElement activeChild = CustomFocusManager.GetFocusedChild(this); + if (activeChild != null) { + LoggingService.Debug("Will move focus to: " + activeChild); + Dispatcher.BeginInvoke(DispatcherPriority.Background, + new Action(delegate { Keyboard.Focus(activeChild); })); + } + } + public bool IsDisposed { get { return false; } } #region IOwnerState