MVVM - Closing Doesn't Remove From DocumentItems

Docking/MDI for WPF Forum

Posted 9 years ago by Justin Klein
Version: 15.1.0623
Avatar

I just noticed that when using the MVVM pattern for docking windows (aka DocumentItemsSource), while adding to the DocumentItems creates a new tab (as expected), closing a tab does not remove it from DocumentItems.  In other words, as soon as you start closing tabs, the DocumentItems becomes "out-of-sync" with the tabs.  If you were to repeatedly open a document, close its tab, reopen it, close its tab, etc - you would end up with an infinitely-growing list of DocumentItems.

My code came directly from the sample project - I only added the ability to open documents.

I'm pretty new to WPF/MVVM, but is this the intended behavior?  My understanding was that the purpose of binding would be to (in this case) always have the DocumentItems represent the tabs, and vice-versa...

Comments (13)

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

Hi Justin,

Yes that is the intended behavior.  The binding doesn't always represent tabs, especially in tool window scenarios since the same tool windows open/close potentially many times over an app lifecycle.  Each docking window has an IsOpen property that tells you whether it is currently visible in the layout (in tabs, etc.).  That being said, when a docking window gets unregistered from the dock site, which happens by default with document windows when they close, the item should be removed from the itemssource.  In the current version, you need to handle the DockSite.WindowUnregistered event and do that manually.

In vNext (massive updates we are doing as detailed in our blog), when a docking window becomes unregistered, it will also attempt to remove the related item from the ToolItemsSource or DocumentItemsSource properties if they implement IList.  If they don't implement IList, then you would need to still do a manual collection modification.  But our automated code should handle most scenarios.


Actipro Software Support

Posted 9 years ago by Justin Klein
Avatar

Is the release of vNext imminent?

I'm just getting started with Actipro (as of a couple weeks ago) and am still developing with the demo; it sounds like a lot of the problems I'm having would be fixed in vNext.  Kind of a shame to be doing all this extra debugging for nothing - or maybe even if the release isn't RIGHT around the corner, I wonder if it makes sense for me to be starting with the beta of vNext, just so I'm not developing brand new code based on a soon-to-be replaced (/improved) platform?

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

Hi Justin,

We are currently widdling down the remaining TODO items and then will start working on prepping things for a beta release.  While we have effectively rewritten much of the product's internals, most of the public API remains the same or at least similar to the current version with the exception of new feature additions of course.  Would you like to sign up to be a beta tester?  We hope to have a beta out in the next 2-3 weeks barring any major issues that arise.


Actipro Software Support

Posted 9 years ago by Justin Klein
Avatar

Ah, understood.  Unfortunately that's outside of my timeline for getting up an initial build of this application, so in that case I should probably just proceed as-is.

So then, returning to your first response: "when a docking window gets unregistered from the dock site, which happens by default with document windows when they close, the item should be removed from the itemssource. In the current version, you need to handle the DockSite.WindowUnregistered event and do that manually"

What I've done thus far is duplicated the entire ActiproSoftware.ProductSamples.DockingSamples.Common code; however, I put a breakpoint in OnDockSiteWindowUnregistered and found that it doesn't seem to be getting called when document tabs are closed.  This was actually the first place I looked, with the expectation that it'd be where I'd manually remove the item - but when it never got called...well..that's when I posted here :)

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

I looked at the code for the current version and it looks like we skip the auto-destroy if the document window is a container for a MVVM item.  I'm not sure of the reasoning why that is there, since it's better for that to happen automatically in my opinion.  At least in vNext, it will do so.

But back on the current version, you'd need to watch the WindowClosed event too and in that handler, call Destroy() on the window if it is a document window.  That will trigger the WindowUnregistered event, from where you can add your logic to alter the itemssource collection.


Actipro Software Support

Posted 9 years ago by Justin Klein
Avatar

Is there no way to do this without breaking MVVM?  I'm just starting out with MVVM, but my beginner's understanding is that the goal is to keep CodeBehind completely empty - my application has *nothing* there thus far, this event handler would be the first.  So unless I'm misunderstanding, it seems pretty strange to me that in order to use MVVM...you have to break MVVM...?

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

In the current version, you do need the event handlers.  While it's not ideal to have to resort to event handlers in MVVM, some scenarios do require it.  But again, vNext changes things so this scenario wouldn't need event handlers.


Actipro Software Support

Posted 9 years ago by Justin Klein
Avatar

Alright, understood.

Just one last thing: you said "That will trigger the WindowUnregistered event, from where you can add your logic to alter the itemssource collection."  Any reason I need to do the removal in WindowUnregistered, & not just in the WindowClosed event handler after calling Destroy()?  

i.e. the following seems to be working fine, just wanted to make sure there isn't some other reason to wait until WindowUnregistered specifically.  Note: I'm using an EventToCommand implementation to route the WindowClosed event directly into my ViewModel as a command:

        RelayCommand _windowClosedCommand;
        public ICommand WindowClosedCommand
        {
            get
            {
                return _windowClosedCommand ?? (_windowClosedCommand = new RelayCommand(param =>
                {
                    if (param is DockingWindowEventArgs)
                    {
                        DockingWindow win = ((DockingWindowEventArgs)param).Window;
                        win.Destroy();
                        DocumentItems.Remove((RadarDocumentViewModel)win.Content);
                    }
                }));
            }
        }
Posted 9 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar

Hi Justin,

That's fine, although you can remove the win.Destroy() call since that will occur from our side if you remove the item from DocumentItems (your next line).


Actipro Software Support

Posted 9 years ago by Justin Klein
Avatar

Perfect, thanks :)

Posted 6 years ago by Matthew Bristow
Avatar

Was this change only implemented for DocumentItemsSource or ToolItemsSource as well?

I can see that removing DocumentWindows updates the DocumentItems collection that is bound to it but removing a ToolWindow does not update the ToolItems collection.

I observed this using your Docking/MDI > MVVM ToolWindows example. 

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

Hi Matthew,

Per the "Lifecycle and Docking Management" documentation topic, document windows destroy (disassociate themselves from the DockSite) when they are closed by default.  You can change that with the DockSite.AreDocumentWindowsDestroyedOnClose property.  However unlike documents, tool windows are designed to stick around to be reopened.  Thus tool windows don't ever auto-destroy themselves on close, and won't remove themselves from a ToolItems collection. 

If you want to destroy a tool window on close, then watch the DockSite.WindowsClosed event and call the tool window's Destroy() method.


Actipro Software Support

Posted 6 years ago by Matthew Bristow
Avatar

I misread this line from you first reply.

In vNext (massive updates we are doing as detailed in our blog), when a docking window becomes unregistered, it will also attempt to remove the related item from the ToolItemsSource..

That is fine. It is how we do it currently.

The latest build of this product (v24.1.2) was released 2 days ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.