1
Vote

[Version 1.3] Add solution to resolve binding problems

description

Hellow! Sorry for my english.
I use AvalonDock 1.3 in my project and find simple way for save all binding and resolve some focus problems.
!!! Use Framework 4.0 or better
 
1) Add into classes DockingManager and FloatingWindow two methods
 
    internal void AddLogicalChild(FrameworkElement frameworkElement)
    {
        base.AddLogicalChild(frameworkElement);
    }
 
    internal void RemoveLogicalChild(FrameworkElement frameworkElement)
    {
        base.RemoveLogicalChild(frameworkElement);
    }
 
2) Modify one method into DockingManagerClass. This way can helps to keep all bindings for commands and properties.
 
private bool flag;
 
    protected virtual void OnActiveContentChanged(DependencyPropertyChangedEventArgs e)
    {
        var cntActivated = e.NewValue as ManagedContent;
        var cntDeactivated = e.OldValue as ManagedContent;
 
        if (cntDeactivated != null)
        {
            cntDeactivated.SetIsActiveContent(false);
        }
 
        if (cntActivated != null)
        {
            cntActivated.SetIsActiveContent(true);
        }
 
        if (cntActivated != null && cntActivated.ContainerPane is DocumentPane)
        {
            ActiveDocument = cntActivated;
        }
 
        var activeContent = cntActivated;
        if (activeContent == null)
        {
            return;
        }
//------------------------------------------------------------------------------------
        var isFloating = VisualTreeHelper.GetParent(activeContent) == null;
 
        if (isFloating)
        {
            flag = true;
 
            var pane = (Pane)LogicalTreeHelper.GetParent(activeContent);
            var window = LogicalTreeHelper.GetParent(pane);
            var floatingWindow = window as FloatingWindow;
            if (floatingWindow != null)
            {
                floatingWindow.RemoveLogicalChild(pane);
                var exclusiveCommandBindings =
                    ParentWindow.CommandBindings.Cast<CommandBinding>().Where(cb => !activeContent.CommandBindings.Contains(cb)).ToList();
                activeContent.CommandBindings.AddRange(exclusiveCommandBindings);
                AddLogicalChild(pane);
            }
        }
        else
        {
            flag = false;
            Win32Helper.SendMessage(hwndSource.Handle, 134, 1, 0);
        }       
//------------------------------------------------------------------------------------
        //for backward compatibility
        NotifyPropertyChanged("ActiveContent");
 
        if (ActiveContentChanged != null)
        {
            ActiveContentChanged(this, EventArgs.Empty);
        }
    }
 
3) Good! Now we resolve some focus problems. This article helps me.
http://blogs.msdn.com/b/visualstudio/archive/2010/03/09/wpf-in-visual-studio-2010-part-3-focus-and-activation.aspx
 
Set this static properties on parent window constructor
        // HwndSource.DefaultAcquireHwndFocusInMenuMode = false;
        Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None;
 
Then add this event handlers to all menus and toolbars wich you use in ParentWindow
 
   private PresentationSource _menuSite;
 
    private void PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        _menuSite = PresentationSource.FromVisual(this);
        if (_menuSite != null)
        {
            InputManager.Current.PushMenuMode(_menuSite);
            e.Handled = true;
        }
    }
 
    private void LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
    {
        if (_menuSite != null)
        {
            InputManager.Current.PopMenuMode(_menuSite);     
            _menuSite = null;
        }
    }
 
4) Okay! Now it's works fine! But when you press on ParentWindow Menu or ToolBars this window shown as active (not like VS2010).
 
Add into DockingManager property
    public Window ParentWindow
    {
        get { return this.GetNearestLogicalAncestor<Window>(); }
    }
 
where extension method
 
    public static TType GetNearestLogicalAncestor<TType>(this DependencyObject dependencyObject) where TType : DependencyObject
    {
        if (dependencyObject == null)
        {
            return null;
        }
 
        var parent = LogicalTreeHelper.GetParent(dependencyObject);
        if (parent is TType)
        {
            return (TType)parent;
        }
 
        return GetNearestLogicalAncestor<TType>(parent);
    }
 
5) Add this hack)
 
    private bool flag;
 
    private HwndSource hwndSource;
 
    private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
    {
        // Trace.WriteLine(msg);
 
        if (msg == 134 && flag)
        {
            handled = true;
            flag = false;
        }
 
        return IntPtr.Zero;
    }
 
    protected void AddHookToParentWindow()
    {
        hwndSource = PresentationSource.FromVisual(ParentWindow) as HwndSource;
 
        if (hwndSource != null)
        {
            hwndSource.AddHook(WndProc);
        }
    }
 
    private void DockingManager_Loaded(object sender, RoutedEventArgs e)
    {
        Debug.WriteLine("DockingManager Loaded");
 
        if (!DesignerProperties.GetIsInDesignMode(this))
        {
            foreach (FloatingWindow floatingWindow in _floatingWindows)
            {
                floatingWindow.Owner = Window.GetWindow(this);
                if (floatingWindow.IsVisible)
                {
                    floatingWindow.Hide();
                }
 
                floatingWindow.Show();
            }
 
            DragPaneServices.Register(this);
        }
 
        AddHookToParentWindow();
        _isControlLoaded = true;
    }
 
This is all.
 
for questions
v-makarevich@mail.ru

file attachments

comments