Activate/Deactive doesn't fire for docking windows

WPF Studio, Themes, and Shared Library for WPF Forum

Posted 15 years ago by Mike Benson
Version: 4.5.0470
Platform: .NET 3.5
Environment: Windows XP (32-bit)
Avatar
I have nailed this down to activate / deactivate not firing for windows that either have null content or content that does not normally receive focus.

In my included example, if you click on the ribbon buttons labeled "Open TB.... " You will note that you cannot activate the tabs or the windows by just clicking on them. If you undock them or something along those lines, the activate/deactivate works for that period only.

However, if you click on the ribbon buttons labeled "Open LB...." the activate / deactivate works as expected.

Here is the XAML:

<Window x:Class="WpfApplication2.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:navigation="http://schemas.actiprosoftware.com/winfx/xaml/navigation"
    xmlns:ribbon="http://schemas.actiprosoftware.com/winfx/xaml/ribbon"
    xmlns:shared="http://schemas.actiprosoftware.com/winfx/xaml/shared"
    xmlns:docking="http://schemas.actiprosoftware.com/winfx/xaml/docking" 
    xmlns:themes="http://schemas.actiprosoftware.com/winfx/xaml/themes"
    Title="Window1" Height="517" Width="559">
    <DockPanel x:Name="DockPanel" themes:ThemeManager.Theme="Office2007Blue">
        <Grid Visibility="Hidden">
            <Grid.RowDefinitions>
                <RowDefinition Height="0"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="0"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Frame
            x:Name="NavigationFrame"
            Grid.Row="0"
            Grid.Column="0"
            Width="0"
            Height="0"
            Visibility="Hidden"/>
        </Grid>


        <shared:PixelSnapper DockPanel.Dock="Top">
            <ribbon:Ribbon x:Name="RibbonStrip" IsQuickAccessToolBarCustomizationEnabled="True" IsCustomizeQuickAccessToolBarMenuItemVisible="True" >
                <ribbon:Ribbon.ContextualTabGroups>
                    <ribbon:ContextualTabGroup Label="View" Name="View" />
                </ribbon:Ribbon.ContextualTabGroups>
                <ribbon:Ribbon.ApplicationMenu>
                    <ribbon:ApplicationMenu />
                </ribbon:Ribbon.ApplicationMenu>
                <ribbon:Ribbon.LayoutTransform>
                    <ScaleTransform ScaleX="{Binding ElementName=ribbonDemo, Path=RibbonScale}" ScaleY="{Binding ElementName=ribbonDemo, Path=RibbonScale}" />
                </ribbon:Ribbon.LayoutTransform>
                <ribbon:Ribbon.TabPanelItems>
                    <ribbon:Button KeyTipAccessText="Z" Command="ApplicationCommands.Help" Name="Help" Label="Help" />
                    <UIElement />
                </ribbon:Ribbon.TabPanelItems>
                <ribbon:Tab Label="Test">
                    <ribbon:Group Label="Test">
                        <ribbon:Button Label="Open TB Document" x:Name="OpenTBDocument" Command="ApplicationCommands.Open" CommandParameter="DOC" ></ribbon:Button>
                        <ribbon:Button Label="Open TB Tool Window" x:Name="OpenTBToolWindow" Command="ApplicationCommands.Open" CommandParameter="TW"></ribbon:Button>
                        <ribbon:Button Label="Open LB Document" x:Name="OpenLBDocument" Command="ApplicationCommands.Open" CommandParameter="DOC2" ></ribbon:Button>
                        <ribbon:Button Label="Open LB Tool Window" x:Name="OpenLBToolWindow" Command="ApplicationCommands.Open" CommandParameter="TW2"></ribbon:Button>
                    </ribbon:Group>
                </ribbon:Tab>
            </ribbon:Ribbon>
        </shared:PixelSnapper>

        <shared:PixelSnapper DockPanel.Dock="Bottom" >
            <StatusBar x:Name="StatusBar" Padding="0,2,0,0" Style="{DynamicResource {x:Static ribbon:RibbonStyles.StatusBarKey}}" >
                <StatusBarItem x:Name="StatusPanelText" Content="Ready" />
            </StatusBar>
        </shared:PixelSnapper>

        <shared:PixelSnapper DockPanel.Dock="Left">
            <navigation:NavigationBar 
                    x:Name="Desktop_SideNavigationBar"
                    HorizontalAlignment="Stretch"
                    VerticalAlignment="Stretch"
                    Margin="0,0,0,0" IsCustomizationEnabled="False" ContentWidth="150">


            </navigation:NavigationBar>
        </shared:PixelSnapper>



        <docking:DockSite Name="docksite">

            <docking:DockSite.AutoHideLeftContainers>
                <docking:ToolWindowContainer Name="West_ToolWindowContainer">
                </docking:ToolWindowContainer>

                <docking:ToolWindowContainer Name="West_West_ToolWindowContainer">
                </docking:ToolWindowContainer>
            </docking:DockSite.AutoHideLeftContainers>

            <docking:DockSite.AutoHideRightContainers>
                <docking:ToolWindowContainer Name="East_ToolWindowContainer">
                </docking:ToolWindowContainer>
                <docking:ToolWindowContainer Name="East_East_ToolWindowContainer">
                </docking:ToolWindowContainer>
            </docking:DockSite.AutoHideRightContainers>

            <docking:SplitContainer >
                <docking:SplitContainer Orientation="Vertical">
                    <docking:Workspace>
                        <docking:TabbedMdiHost IsCloseButtonOnTab="True" TabPlacement="Top" x:Name="TabbedMdiHost" >
                            <docking:TabbedMdiContainer x:Name="NavigationTab" >
                            </docking:TabbedMdiContainer>
                        </docking:TabbedMdiHost>
                    </docking:Workspace>
                    <docking:ToolWindowContainer Name="South_South_ToolWindowContainer">
                        <docking:ToolWindow x:Name="outputToolWindow" Title="Output" CanClose="false"  >
                            <ListBox x:Name="eventsListBox" BorderThickness="0" />
                        </docking:ToolWindow>
                    </docking:ToolWindowContainer>
                </docking:SplitContainer>
                <docking:ToolWindowContainer Name="South_East_ToolWindowContainer">
                </docking:ToolWindowContainer>
            </docking:SplitContainer>
        </docking:DockSite>
    </DockPanel>
</Window>
Here is the code behind

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ActiproSoftware.Windows.Controls.Docking;

namespace WpfApplication2
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {

        

        public Window1()
        {
            InitializeComponent();

            this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, this.OpenExecuted, this.OpenCanExecute));

            docksite.WindowActivated += new EventHandler<DockingWindowEventArgs>(docksite_WindowActivated);
            docksite.WindowDeactivated += new EventHandler<DockingWindowEventArgs>(docksite_WindowDeactivated);
            docksite.WindowOpened += new EventHandler<DockingWindowEventArgs>(docksite_WindowOpened);
            docksite.WindowClosing += new EventHandler<DockingWindowEventArgs>(docksite_WindowClosing);
            docksite.WindowOpening += new EventHandler<DockingWindowEventArgs>(docksite_WindowOpening);
        }

        void docksite_WindowOpening(object sender, DockingWindowEventArgs e)
        {
            this.AppendMessage(String.Format("Window Opening: Name={0}", e.Window.Title));
        }

        void docksite_WindowClosing(object sender, DockingWindowEventArgs e)
        {
            this.AppendMessage(String.Format("Window Closing: Name={0}", e.Window.Title));
        }

        void docksite_WindowOpened(object sender, DockingWindowEventArgs e)
        {
            this.AppendMessage(String.Format("Window Opened: Name={0}", e.Window.Title));
        }

        void docksite_WindowDeactivated(object sender, DockingWindowEventArgs e)
        {
            this.AppendMessage(String.Format("Window Deactivated: Name={0}", e.Window.Title));
        }

        void docksite_WindowActivated(object sender, DockingWindowEventArgs e)
        {
            this.AppendMessage(String.Format("Window Activated: Name={0}", e.Window.Title));
        }

        private int windownum = 0;

        private void OpenExecuted(object target, ExecutedRoutedEventArgs e)
        {
            try
            {
                int wn = windownum++;

                if (string.Equals(e.Parameter, "TW"))
                {

                    ToolWindow tw = new ToolWindow(this.docksite, "TW" + wn, "Toolwindow" + wn, null, new TextBlock());
                    tw.Dock(this.docksite, Direction.Bottom);
                    tw.Activate();
                }
                else if (string.Equals(e.Parameter, "DOC"))
                {
                    DocumentWindow dw = new DocumentWindow(this.docksite, "DOC" + wn, "Document" + wn, null, new TextBlock());
                    dw.Activate();
                }
                if (string.Equals(e.Parameter, "TW2"))
                {

                    ToolWindow tw = new ToolWindow(this.docksite, "TW" + wn, "Toolwindow" + wn, null, new ListBox());
                    tw.Dock(this.docksite, Direction.Bottom);
                    tw.Activate();
                }
                else if (string.Equals(e.Parameter, "DOC2"))
                {
                    DocumentWindow dw = new DocumentWindow(this.docksite, "DOC" + wn, "Document" + wn, null, new ListBox());
                    dw.Activate();
                }
            }
            catch (Exception)
            {

                throw;
            }
        }
        private void OpenCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

        private void AppendMessage(string text)
        {
            ListBoxItem item = new ListBoxItem();
            item.Content = text;
            eventsListBox.Items.Add(item);
            eventsListBox.SelectedItem = item;
            eventsListBox.ScrollIntoView(item);
        }
    }
}

Comments (12)

Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Mike,

Without actually running the code, my guess is that the problem is because you add a TextBlock child control which is not capable of being focused. If you would add a focusable control, then it should work. Maybe you could even just set Focusable=true on the TextBlocks to get it working.


Actipro Software Support

Posted 15 years ago by Mike Benson
Avatar
Your workaround does do the trick. However, that means that users can click on my non-focusable controls and get the focus; this looks a bit funky for status type windows.

It seems to me that if the user clicks on the title bar of tool window or document the tool window should know its been activated.

Put me in for this feature request...
Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Mike,

We've updated code for the next release to be able to click on the title bars and tabs of tool windows containing non-focusable content, and have the tool window appear focused.


Actipro Software Support

Posted 15 years ago by Mike Benson
Avatar
Wow, very impressive. Have to say Actipro has the best support I've ever experienced.

Thanks.
Posted 15 years ago by Frank Bell
Avatar
I am having a similar problem, whereby I have a user control (which simply contains a WPF WebBrowser control) hosted within a DocumentWindow set to occupy all available space.

When clicking on the document window, the tab is changing correctly and I can interact with it, but the WindowActivated/WindowDeactivated events are not firing.

If I then place a textbox onto the the user control, and then start debugging and navigate to the document window containing the user control, the WindowActivated/WindowDeactivated events are fired, but only when clicking into the textbox.

I have tried setting Focusable to true (along with a variety of other properties) but with no luck. It would be good to know what is required before the WindowActivated event is fired to try come up with a workaround.

PS - The reason that I am using the WindowActivated/WindowDeactivated events is to maintain which control is currently active so that I can bind to its data context to detect if changes have been made in order to show/hide a global save button.
Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Frank,

The action of setting DockSite.ActiveWindow triggers those events. And that property is usually set based on keyboard focus tracking. WinForms interop is notoriously bad in WPF when related to keyboard focus unfortunately.

I would suspect that since your WebBrowser is probably getting the focus, but the proper WPF events aren't bubbling up to us, we aren't setting that property and thus the events don't fire.

If you want, you can make a simple sample project that shows the issue and we can take a look to see if there's anything we can do.


Actipro Software Support

Posted 15 years ago by Frank Bell
Avatar
Hey,

You mentioned WinForms interop, but I am using the WPF version of the WebBrowser control which is part of .Net Framework 3.5 service pack 1 (http://msdn.microsoft.com/en-us/library/system.windows.controls.webbrowser.aspx).

I can try and put together a sample application, but in the mean time could you possibly provide a list of events that DockSite.ActiveWindow?

Frank
Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Well really ANY sort of interop has these issues, not just Windows Forms. Even the WPF WebBrowser is interop of some kind behind the scenes because it's certainly not a native WPF control (the part that renders content at least) and is probably just a wrapped IE instance.

As for where ActiveWindow is set, it's in OnPreviewGotKeyboardFocus of root containers like DockHost.


Actipro Software Support

Posted 15 years ago by Frank Bell
Avatar
I would of thought that it being WPF it would've had to at least conform to some sort of standard. :)

Thanks for the information on the OnPreviewGotKeyboardFocus, I will play around with that and see if I can establish a workaround.

Thanks for your help.
Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Please do let us know if you find anything. We're doing some work now on improving interoped control support in Docking & MDI.


Actipro Software Support

Posted 15 years ago by Sébastien Van Bruaene
Avatar
Product Version: WPF Studio v4.5.0485 (no windows forms interop)
System: .NET 3.5, Windows Vista, 32-bit

Hello I still experience the bug described above : If I click on a tab with all controls disabled or with no content at all the window activated event does not fire. This is a huge problem for me I need to be notified when the visible document changes even is all controls are disabled. It this resolved yet or is there a work around for this problem ?

[Modified at 02/18/2009 03:47 AM]
Posted 15 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Sébastien,

That sort of thing should have been fixed in a previous release. Can you put together a simple sample project that shows it happening if you are sure you're on the latest build, and email it over to our support address? We'll debug it and take a look. Thanks!


Actipro Software Support

The latest build of this product (v24.1.1) was released 1 month ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.