How to catch event Closing or analog for DocumentWindow?

Docking/MDI for WPF Forum

Posted 9 years ago by Alexander Tokarenko
Version: 10.1.0523
Avatar
I use the TabbedMdiContainer object for keeping some DocumentWindow objects. And I need to check if some changes were made in the document before window will be closed. And so I need a way to catch the analog of Closing event for Window object. How can I do that? Thank you

Comments (8)

Posted 9 years ago by Alexander Tokarenko
Avatar
Also I need to catch events when opened DocumentWindows are activated.

[Modified at 07/12/2010 09:32 AM]
Posted 9 years ago by Mick George - Software Engineer, CNC Software, Inc.
Avatar
Hi Alex,

If I understand you correctly what I do is register a docksite window closing event in our editor view and test for a modified document there.

EventManager.RegisterClassHandler(typeof(DockSite), DockSite.WindowClosingEvent, new RoutedEventHandler(this.DockSite_WindowClosing));

/// <summary>
        /// Handles the <c>WindowClosing</c> event of the <c>DockSite</c> control.
        /// </summary>
        /// <param name="sender">The source of the event</param>
        /// <param name="e">A <see cref="DockingWindowEventArgs"/> that contains the event data.</param>
        public void DockSite_WindowClosing(object sender, RoutedEventArgs e)
        {
            // Get the DockSite
            DockSite docksite = sender as DockSite;

            // Cast to our window event args
            DockingWindowEventArgs arg = e as DockingWindowEventArgs;

            // Get the active document window
            DocumentView window = arg.Window as DocumentView;

            // If its not a Document Window 
            if (null != window)
            {
                // Get the syntax editor
                ItemsControl control = window.Content as ItemsControl;
                SyntaxEditor editor = control.Items.CurrentItem as SyntaxEditor;

                if (null != editor)
                {
                    // Is document dirty?
                    if (editor.Document.IsModified)
                    {
Posted 9 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Alexander,

You can attach a handler to the DockSite.WindowClosing and/or DockSite.WindowActivated events. The associated window is specified by the e.Window property. The Docking & MDI Features demos show one way to attach to these events.

Micks method above will work globally across all instances of DockSite. If you only have 1 DockSite in your application, you can usually just attach to the instance events directly.


Actipro Software Support

Posted 9 years ago by Alexander Tokarenko
Avatar
Thank you. If I understand you correctly then windows doesn't have active and close events. But the DockSite has these events instead? So I have 1 DockSite and in the my case it will be simply like following^:

<docking:DockSite Grid.Row="2" Name="m_DockSite" WindowClosing="m_DockSite_WindowClosing">
            <docking:SplitContainer>
                <docking:ToolWindowContainer>
                    <docking:ToolWindow Name="m_ToolWndProcTree" Title="{Resx ResxName=Technologist.MainFrameWnd, Key=ToolWndProcessesTree}">
                        
                    </docking:ToolWindow>
                    <docking:ToolWindow Name="m_ToolWndProcStruct" Title="{Resx ResxName=Technologist.MainFrameWnd, Key=ToolWndProcessStructure}">
                        
                    </docking:ToolWindow>
                </docking:ToolWindowContainer>

                <docking:SplitContainer>

                    <docking:Workspace>
                        <docking:TabbedMdiHost>
                            <docking:TabbedMdiContainer Name="m_DocContainer">
    
                            </docking:TabbedMdiContainer>
                        </docking:TabbedMdiHost>
                    </docking:Workspace>

                    <docking:ToolWindowContainer>
                        <docking:ToolWindow Name="m_ToolWndToolBox" Title="{Resx ResxName=Technologist.MainFrameWnd, Key=ToolWndToolBox}">
                            <mf:NodeListView Name="m_ToolboxListView"
                                             Style="{StaticResource ToolBoxListView}">
                            </mf:NodeListView>
                        </docking:ToolWindow>
                    </docking:ToolWindowContainer>

                </docking:SplitContainer>
            </docking:SplitContainer>
        </docking:DockSite>
Posted 9 years ago by Alexander Tokarenko
Avatar
Thank you. If I understand you correctly then windows doesn't have active and close events. But the DockSite has these events instead? So I have 1 DockSite and in the my case it will be simply like following^:

<docking:DockSite Grid.Row="2" Name="m_DockSite" WindowClosing="m_DockSite_WindowClosing">
            <docking:SplitContainer>
                <docking:ToolWindowContainer>
                    <docking:ToolWindow Name="m_ToolWndProcTree" Title="{Resx ResxName=Technologist.MainFrameWnd, Key=ToolWndProcessesTree}">
                        
                    </docking:ToolWindow>
                    <docking:ToolWindow Name="m_ToolWndProcStruct" Title="{Resx ResxName=Technologist.MainFrameWnd, Key=ToolWndProcessStructure}">
                        
                    </docking:ToolWindow>
                </docking:ToolWindowContainer>

                <docking:SplitContainer>

                    <docking:Workspace>
                        <docking:TabbedMdiHost>
                            <docking:TabbedMdiContainer Name="m_DocContainer">
    
                            </docking:TabbedMdiContainer>
                        </docking:TabbedMdiHost>
                    </docking:Workspace>

                    <docking:ToolWindowContainer>
                        <docking:ToolWindow Name="m_ToolWndToolBox" Title="{Resx ResxName=Technologist.MainFrameWnd, Key=ToolWndToolBox}">
                            <mf:NodeListView Name="m_ToolboxListView"
                                             Style="{StaticResource ToolBoxListView}">
                            </mf:NodeListView>
                        </docking:ToolWindow>
                    </docking:ToolWindowContainer>

                </docking:SplitContainer>
            </docking:SplitContainer>
        </docking:DockSite>
Posted 9 years ago by Alexander Tokarenko
Avatar
Hi, all.
I creates the DocumentWindow object by this function:

        void AddNewDocWnd(String a_sTitle, TPDEDiagram a_Dgrm, bool a_bActivate)
        {
            DocumentWindow wnd = CreateNewDoc(a_sTitle);
            SqlHierarchyId parentId = App.m_DbSim.GetId(SqlHierarchyId.Null);
            a_Dgrm.Id = App.m_DbSim.AddProcess(parentId);
            a_Dgrm.InitBreadcrumb();
            wnd.Content = a_Dgrm;
            m_DocContainer.Items.Add(wnd);
            if (a_bActivate) wnd.Activate(true);
        }
m_DocContainer is the TabbedMdiContainer object.
And this function calls when main window is loaded. After that I closes the DocumentWindow. This means that there are no DocumentWindow objects into the workspace. After that I want to create new window by the same call of AddNewDocWnd function. And after call wnd.Activate(true) I see the unhandled exception as follwoing:
A first chance exception of type 'System.InvalidOperationException' occurred in ActiproSoftware.Docking.Wpf351.dll
System.InvalidOperationException: This operation is invalid since the DockingWindow has not yet been registered with a DockSite.
at ActiproSoftware.Windows.Controls.Docking.DockingWindow.Activate(Boolean focus)
at Technologist.MainFrameWnd.AddNewDocWnd(String a_sTitle, TPDEDiagram a_Dgrm, Boolean a_bActivate) in D:\Work\TPDE\Technologist\MainFrameWnd.xaml.cs:line 88
at Technologist.MainFrameWnd.NewDgrm_Executed(Object sender, ExecutedRoutedEventArgs e) in D:\Work\TPDE\Technologist\MainFrameWnd.xaml.cs:line 475
at System.Windows.Input.CommandBinding.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
at System.Windows.Input.CommandManager.ExecuteCommandBinding(Object sender, ExecutedRoutedEventArgs e, CommandBinding commandBinding)
at System.Windows.Input.CommandManager.FindCommandBinding(CommandBindingCollection commandBindings, Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
at System.Windows.Input.CommandManager.FindCommandBinding(Object sender, RoutedEventArgs e, ICommand command, Boolean execute)
at System.Windows.Input.CommandManager.OnExecuted(Object sender, ExecutedRoutedEventArgs e)
at System.Windows.UIElement.OnExecutedThunk(Object sender, ExecutedRoutedEventArgs e)
at System.Windows.Input.ExecutedRoutedEventArgs.InvokeEventHandler(Delegate genericHandler, Object target)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.RoutedCommand.ExecuteImpl(Object parameter, IInputElement target, Boolean userInitiated)
at System.Windows.Input.RoutedCommand.ExecuteCore(Object parameter, IInputElement target, Boolean userInitiated)
at MS.Internal.Commands.CommandHelpers.CriticalExecuteCommandSource(ICommandSource commandSource, Boolean userInitiated)
at System.Windows.Controls.Primitives.ButtonBase.OnClick()
at System.Windows.Controls.Button.OnClick()
at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
at System.Windows.UIElement.OnMouseLeftButtonUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.ReRaiseEventAs(DependencyObject sender, RoutedEventArgs args, RoutedEvent newEvent)
at System.Windows.UIElement.CrackMouseButtonEventAndReRaiseEvent(DependencyObject sender, MouseButtonEventArgs e)
at System.Windows.UIElement.OnMouseUpThunk(Object sender, MouseButtonEventArgs e)
at System.Windows.Input.MouseButtonEventArgs.InvokeEventHandler(Delegate genericHandler, Object genericTarget)
at System.Windows.RoutedEventArgs.InvokeHandler(Delegate handler, Object target)
at System.Windows.RoutedEventHandlerInfo.InvokeHandler(Object target, RoutedEventArgs routedEventArgs)
at System.Windows.EventRoute.InvokeHandlersImpl(Object source, RoutedEventArgs args, Boolean reRaised)
at System.Windows.UIElement.RaiseEventImpl(DependencyObject sender, RoutedEventArgs args)
at System.Windows.UIElement.RaiseEvent(RoutedEventArgs args, Boolean trusted)
at System.Windows.Input.InputManager.ProcessStagingArea()
at System.Windows.Input.InputManager.ProcessInput(InputEventArgs input)
at System.Windows.Input.InputProviderSite.ReportInput(InputReport inputReport)
at System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr hwnd, InputMode mode, Int32 timestamp, RawMouseActions actions, Int32 x, Int32 y, Int32 wheel)
at System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndWrapper.WndProc(IntPtr hwnd, Int32 msg, IntPtr wParam, IntPtr lParam, Boolean& handled)
at MS.Win32.HwndSubclass.DispatcherCallbackOperation(Object o)
at System.Windows.Threading.ExceptionWrapper.InternalRealCall(Delegate callback, Object args, Boolean isSingleParameter)
at System.Windows.Threading.ExceptionWrapper.TryCatchWhen(Object source, Delegate callback, Object args, Boolean isSingleParameter, Delegate catchHandler)
What happens?
Posted 9 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Alexander,

In the future, please create a new forum post or support ticket for sepearate questions.

That is correct, the events are raised by the DockSite and what you have is fine.

When you construct DocumentWindows or ToolWindows programmatically, you must pass a DockSite in the constructor to "register" it. Otherwise, the call to Activate has no idea where you want to open the window. Our Sample Browser has several examples that show how to do this, such as the Features demo. Specfically, you can look in the MainControl.CreateTextDocumentWindow method in the "ProductSamples\DockingSamples\Demo\Features" folder.

Also, you should not name or reference any ToolWindowContainer, TabbedMdiContainer, or SplitContainer as these items are dynamically created and destroyed as windows are opened, closed, or moved around. Again, if you follow how the Features demo calls things, it should work fine. Specifically, you'd call the Open method. Keep in mind that calling Activate will call Open if the window is not already open.


Actipro Software Support

Posted 9 years ago by Alexander Tokarenko
Avatar
Thanks a lot.
The latest build of this product (v2019.1 build 0683) 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.