Can't find all child documentwindows inside raftingwindow

Docking/MDI for WPF Forum

Posted 3 years ago by Mark Bonner
Version: 16.1.0634
Platform: .NET 4.5
Environment: Windows 10 (64-bit)
Avatar

Please see the serialisation below to understand the layout.

We need to be able to create new floating windows containing all child objects. This is all working fine and creates the RaftingWindows below. However, if I then add another DockSite (containing one or more DocumentWindows) to a floating window I can't determine it's parent programmatically? 

How do I find the container programmatically (which relates to the RaftingWindow or TabMdiContainer)?

 

<SerializedLayout>&lt;DockSiteLayout xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SerializationFormat="All" Version="2"&gt;
&lt;AutoHideHost /&gt;
&lt;Content xsi:type="Workspace"&gt;
&lt;Content xsi:type="TabbedMdiHost"&gt;
&lt;Content xsi:type="TabbedMdiContainer" SelectedWindowUniqueId="57a2da6a-4deb-47d1-814b-91c558ab299c"&gt;
&lt;UIElement xsi:type="DocumentWindowRef" UniqueId="57a2da6a-4deb-47d1-814b-91c558ab299c" /&gt;
&lt;/Content&gt;
&lt;/Content&gt;
&lt;/Content&gt;
&lt;DocumentWindows&gt;
&lt;DocumentWindow UniqueId="57a2da6a-4deb-47d1-814b-91c558ab299c" SerializationId="Page1e3fedd6aa0f4ae680a215b4d66d0761" IsOpen="true" State="Document" /&gt;
&lt;DocumentWindow UniqueId="ac95803a-bcc8-4501-a3c5-f8dcb8fd5222" SerializationId="Page8c9c1aa80dc34fad906eb94c26fbc52a" IsOpen="true" State="Document" /&gt;
&lt;DocumentWindow UniqueId="71aebd28-09f7-46c8-9ad7-89f9c1f76ec3" SerializationId="Page9a018968eaae41ffa177328f3f90e235" IsOpen="true" State="Document" /&gt;
&lt;/DocumentWindows&gt;
&lt;RaftingHosts&gt;
&lt;RaftingHost UniqueId="67db9147-b305-4de3-96f4-c7372cf1967f" IsMaximized="false" Location="0,55" Size="1692,436"&gt;
&lt;AutoHideHost /&gt;
&lt;Content xsi:type="Workspace"&gt;
&lt;Content xsi:type="TabbedMdiHost"&gt;
&lt;Content xsi:type="TabbedMdiContainer" SelectedWindowUniqueId="ac95803a-bcc8-4501-a3c5-f8dcb8fd5222"&gt;
&lt;UIElement xsi:type="DocumentWindowRef" UniqueId="ac95803a-bcc8-4501-a3c5-f8dcb8fd5222" /&gt;
&lt;/Content&gt;
&lt;/Content&gt;
&lt;/Content&gt;
&lt;/RaftingHost&gt;
&lt;RaftingHost UniqueId="dcad8334-f0ea-48fe-8528-088341c39efb" IsMaximized="false" Location="0,55" Size="1692,436"&gt;
&lt;AutoHideHost /&gt;
&lt;Content xsi:type="Workspace"&gt;
&lt;Content xsi:type="TabbedMdiHost"&gt;
&lt;Content xsi:type="TabbedMdiContainer" SelectedWindowUniqueId="71aebd28-09f7-46c8-9ad7-89f9c1f76ec3"&gt;
&lt;UIElement xsi:type="DocumentWindowRef" UniqueId="71aebd28-09f7-46c8-9ad7-89f9c1f76ec3" /&gt;
&lt;/Content&gt;
&lt;/Content&gt;
&lt;/Content&gt;
&lt;/RaftingHost&gt;
&lt;/RaftingHosts&gt;
&lt;/DockSiteLayout&gt;</SerializedLayout>

Comments (16)

Posted 3 years ago by Mark Bonner
Avatar

The rafting objects are actually serialised as RaftingHost instances. How can I programmatically see these objects once they're de-serialised? Currently I'm just seeing a collection of DockSites, some floating and some not.

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

Hi Mark,

I'm sorry but I'm not clear on your scenario and what the question is, and may need more detail.  But if it helps, DockSite.PrimaryDockHost gives you the DockHost that is embedded in the DockSite's control template and DockSite.FloatingDockHosts gives you all of the ones that are in floating windows.

[Modified 3 years ago]


Actipro Software Support

Posted 3 years ago by Mark Bonner
Avatar

Hi,

I agree with your response. Let me try to explain our specific issue.

The operator will create on the primary screen multiple tabbed DockSites, with each DockSite containing a number of Displays. This content can then be used to analyse one individuals performance. Now to compare a second individual requires a copy of all the tabbed DockSites and their Displays into a floating window that can be moved to a second screen. 

Now, I need to be able to send a single command that's received by all tabbed DockSite ViewModels on a given screen (we're calling Page Group). This is fine, but if I add an additional tabbed DockSite I can find it's host owner - is it on screen 1 or screen 2. I can follow the approach you mentioned above, as I believe all non-floating DockSites will be on screen 1 and all floating DockSites on screen 2. 

The main problems is that I might want to compare 3, 4 or more individuals, each with their respective screen. So all tabbed DockSites on screen 2, screen 3, etc, will be floating, so I can't send a command to just the DockSite ViewModels for screen 2 unless I have a hierarchical structure.

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

Hi Mark,

Thanks for the info.  While nested DockSite hierarchies like what you describe are fully supported, our Docking/MDI product doesn't track any sort of hierarchy between them by default.  Because the root DockSite document windows you describe could contain any WPF content.  In your case it includes a nested DockSite.

I assume that based on your description, you have one root DockSite and zero to many nested DockSites, where is nested DockSite is within a root DockSite's document window.  Each DockSite has a PrimaryDockHost presented within the DockSite itself, and zero to many FloatingDockHosts.  The key to doing what you want is probably to get access to all of the nested DockSites. 

For each DockSite you have, you could iterate the PrimaryDockHost and all FloatingDockHosts and on each of those, use Window.GetWindow(dockHost) to find the WPF Window that contains the DockHost.  Then use that Window's bounds to see which screen it's on.  That will tell you where each is.

Hope that helps!


Actipro Software Support

Posted 3 years ago by Mark Bonner
Avatar

Thanks - I'll give it a go :-)

Posted 3 years ago by Mark Bonner
Avatar

It seems that this process will work, but have a couple of issues...

When adding a DockSite we firstly add a ViewModel, resulting in the DockSite being added into the View layer. During the instantiation and linking of Docksites the new object doesn't have a HostWindow or an assigned DataContext. This must happen at a later time, so is there an Actipro event I can use to know the DockSite is fully initialized. At which point, I can query the DockSite's host via Window.GetWindow(). 

I'll keep an in-memory object relationship of hosting window to DockSites, so presumably I can use the HostingWindow.HwndSourceWindow as an Identifier?

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

Hi Mark,

When you use our MVVM features, you can watch for the DockSite.WindowsOpened event.  That will fire after a docking window is opened anywhere into the visual layout.  At the time that event fires, it should have the DataContext of your VM.

Keep in mind that as layout changes (drags, floats, etc.) occur, a docking window might move to another DockHost in the same DockSite, or even another DockHost in another DockSite (but this only if you are linking DockSites).  Each DockHost can be hosted in a different WPF Window and that could change with layout changes too, so be careful with caching any object relationships.  It might be better to get the WPF Window instances on the fly as needed.


Actipro Software Support

Posted 3 years ago by Mark Bonner
Avatar

Hi,

So we're having a discussion here on possible alternatives, so before we continue can I just check whether they'd be any other possible solutions to this problem, such as adding an additional object layer?

Currently we are thinking...

Objective

See previous emails for description. But in summary, we shall create a copy of Pages (DockSites) and child Displays (ToolWindows) for hosting on separate pages, with these copies called PageGroups. These can be persisted (defined in the previous email) and reloaded. 

The operator will create on the primary screen multiple tabbed DockSites, with each DockSite containing a number of Displays. This content can then be used to analyse one individuals performance. Now to compare a second individual requires a copy of all the tabbed DockSites and their Displays into a floating window that can be moved to a second screen.

Now, I need to be able to send a single command that's received by all tabbed DockSite ViewModels on a given screen (we're calling Page Group). This is fine, but if I add an additional tabbed DockSite I can find it's host owner - is it on screen 1 or screen 2. I can follow the approach you mentioned above, as I believe all non-floating DockSites will be on screen 1 and all floating DockSites on screen 2.

The main problems is that I might want to compare 3, 4 or more individuals, each with their respective screen. So all tabbed DockSites on screen 2, screen 3, etc, will be floating, so I can't send a command to just the DockSite ViewModels for screen 2 unless I have a hierarchical structure.

Create Page Group

Monitor DockSite’s Window Open event. Use WPF Windows.GetWindow() to obtain parent Window. Add PageGroupViewModel with parent Window handle as reference. The Primary Page Group will have a MainWindow handle.

Delete Page Group

Monitor DockSite Window Close event. Use WPF Windows.GetWindow() to obtain parent Window (as long as the reference has not been lost). Query all PageGroupViewModels via PageGroupManager and remove where handles match. If the Parent Window reference has been lost then all existing DockSites will need querying to build a list of hosting window handles. These can be used to compare again the PageGroupViewModel handle collection and remove accordingly.

Perform Page Group CompositeSessionContainer Selection

Query all DockSites and use WPF Windows.GetWindow() to obtain all handles. Filter collection by Windows handle matching selected Page Group reference. Reference each DockSite.DataContext to obtain PageViewModel and perform CompositeSessionContainer selection against each PageViewModel.Display collection.

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

Hi Mark,

To summarize from my conversations with Gareth, your Docking/MDI layout is such that you have a root DockSite right now that has mutiple tabbed MDI document windows, where each one of those document windows is a "page" of data for a specific individual.  You can have multiple "pages" (and thus multiple document windows) for an individual.  Each "page" has a nested DockSite in it and that hosts multiple tool window "displays".  These "displays" can be dragged amongst the various "pages" via our linked DockSite feature. 

I'm not thinking you should add another level of hierarchy to add support for viewing a second individual.  I think what you could probably do is just add more "pages" to the existing root DockSite.  As long as each "page" has a reference to which individual it is for, you should be able to know what page is for what.  When you go to build up UI for the second individual, you'd basically run through your root DockSite (or its related root view model) and look for all document windows (or page view models) that are for the first individual.  Clone those and add the clones to the root view model.  Then float the first document window that was created for the second individual to the second screen.  And attach all the other document windows for the second individual to that first document window that was floated.  That will get them all onto the second screen.

As you said, you can probably watch some of our events from that point on to know if additional document windows are opened or closed and adjust things in response.

Keep in mind that any document window ("page") or tool window ("display") that is floated will be in a hierarchy that is hosted by a DockHost.  And again, there is a primary DockHost implicitly defined in each DockSite too.  Each DockHost can be within a separate WPF Window.  So it's probably best to enumerate through the nested DockSites, and enumerate through each of their floating DockHosts, and get the Window of each of those to build up any lists you have.  I'd recommend doing this on the fly since layout changes can cause things to shift sometimes.


Actipro Software Support

Posted 3 years ago by Mark Bonner
Avatar

Thank you for your assistance

Posted 3 years ago by Mark Bonner
Avatar

Hi,

I agreement with all you said during the creation of our a PageGroup (Floating Window). However, on closer inspection their is still one problem.

1. Obtaining a unique identifier for the PageGroup (Floating Window)

When creating a new PageGroup I receive multiple override calls again the Primary DockSite. These include OnWindowRegistered, OnWindowsClosed, OnWindowsOpen and OnFloatingWindowOpening. 

In all cases except OnFloatingWindowOpening the DockingWindowsEventArgs are raised off the Primary DockSite. Only the OnFloatingWindowOpening FloatingWindowOpeningEventArgs.DockHost contains the new object, which I can use to obtain the Windows Handle via Window.GetWindow(). However, I can't distinguish between the operation of Creating a PageGroup or just dragging a Page from any existing window (primary or floating).

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

Hi Mark,

If you are using our MVVM (I believe you are) then the event args for events like WindowsOpened/WindowsClosed pass in e.Windows.  This contains the docking windows being opened/closed.  Each docking window's DataContext should be set to the view model you supplied to the DockSite.  This works similar to a normal ItemsControl.  By looking at that, you should be able to determine what each window is for (a page for a certain individual, etc.).

WindowsOpened only fires when docking windows are added (opened) into the layout.  It won't fire was you drag to float a docking window.


Actipro Software Support

Posted 3 years ago by Mark Bonner
Avatar

Great thanks!!

Posted 3 years ago by Mark Bonner
Avatar

Hi,

So just to recap, we can successful create PageGroups from a single command, which will create a new floating window containing a copy of all associated children. The problem is maintaining a relationship of the PageGroup to the Pages, which doesn't require the continuous monitoring of Pages as they're dragged in and out of the HostingWindow.

As suggested previously, it would be ideal if I could filter all the current PageViewModel children at the time of sending the single PageGroup command. But, that requires a reference back to the HostingWindow, or some other 1:1 relationship. 

So, when performing a single operation against all PageViewModels within the floating window, I can query all DockSites and find those with a matching HostingWindow handle, then use the DataContext from all matching DockSites to retrieve my collection of PageViewModels. But this requires a reference to the HostingWindow at the time of creation. 

DockSite.OnFloatingWindowOpening FloatingWindowOpeningEventArgs provided a e.DockHost. This return a HostingWindow, which is ideal, but unfortunately at this time the windows handle is zero.

Posted 3 years ago by Mark Bonner
Avatar

I've managed to achieve what's required by using the DockHost.UniqueId.

Once again, thanks for your assistance.

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

Hi Mark,

I assume that by "page group" you mean the view model used to track app the "pages" for an individual?  If "pages" are the root view models used in the root DockSite's DocumentsItemsSource and you potentially have a mix of them in there from various "page groups", can't you just store some variable on your "page" view model saying which "page group" it belongs to?  Or am I misunderstanding and "page group" means something else? 

Anyhow, I'm glad you got the unique ID to work for your needs.


Actipro Software Support

The latest build of this product (v2019.1 build 0681) 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.