Hi,
I just ran into a problem I (or a tester) should have noticed a long time ago.
Let's say I have a usercontrol which contains a dock manager, which contains a number of panes, each with a different usercontrol.
The user controls in the panes are "dumb" - the main usercontrol (the one that owns the dock manager) has routed command bindings, and supplies data for the controls to display. If, for example, the user clicks on a row in a XamDataGrid in a control, it executes a routed command that is defined in the main control. The main control does whatever has to be done, and updates the datacontext of the various panes.
This works as long as all the panes are docked. However, I just noticed that if I undock a pane that hosts a usercontrol that uses a routed command and leave the pane floating, then the routed command never gets executed. This actually makes sense (I think): When a pane is floating, it's no longer part of the element tree of the main usercontrol like it was while docked (I sort of confirmed that with Snoop.)
Any suggestions as to how to handle this kind of interaction without using routed commands? I'm kind of scr***d here!
Thanks,Michel
One thing that you could do is to handle the ToolWindow(Loaded|Unloaded) events. When a ToolWindow is loaded you could add command bindings to it so that you could get the routed commands that bubble up to it and then hand them off to the usercontrol to handle (or use the same methods for the handler). When the ToolWindowUnloaded is invoked you probably want to unhook/remove those bindings so you don't root the toolwindows.
Hmmm... Is the ToolWindow in the same visual tree as the "main" usercontrol though? I actually haven't dealt with that class yet.
No its not in the same visual tree which is why you're not getting any commands from within it routing to your user control. ToolWindow is a class we have that is used to host "floating" content. In a standard WPF implementation that means they are hosted in a WPF window that contains the ToolWindow and its contents.
OK. I'll have to experiment a bit with this - I'm not sure how the ToolWindow will (1) be able to handle the command and (2) talk to the usercontrol, which is not in the visual tree...
I have this exact problem
Did you solve this? If so could you by chance post some code?
No - there were other priorities, so I ended up disabling the ability to drag the panes out of the dock manager. I have to get back to this sometime, though I have no idea what approach to use.
If Pinned state of ContentPane changes I experienced that loaded event of all controls in it (UserControl and its child control) gets fired. This thing resets the settings I applied in the loaded event of Usercontrol and its child control.
Why Loaded event of each contol in ContentPane gets fired on Pinned State change..?
If this is a bug then in which version it is resolved..? I am using v9.2 (9.2.20092.2094).
Thanks Andrew
Works great!
Hi Andrew,
Yeah I had no idea what to do with that ToolWindow the last time (the online help is of little help), so I just went on to more pressing matters. I just tried the code you posted and this seems to work perfectly. Thanks a lot!!
Michel
So just to be clear, you have commands associated with commandsource elements (e.g. a Button with the Command set to some routed command). Once the pane is floating the ancestor of the xamDockManager which was handling (either via events or commandbindings) the CanExecute/Execute for those commands is no longer getting those calls for the floating panes. If that's the case then you can work around this by handling the ToolWindowLoaded as I mentioned originally. Then you can either add CommandBindings to the ToolWindow or better still handle the CanExecute/Execute generically and reraise them on the dockmanager. In thinking about this it seems like the xamDockManager should do this itself so I'm going to write up an issue for this but in the interim you can do something like the following to delegate the CanExecute/Execute.
private static void OnToolWindowCanExecuteCommand(object sender, CanExecuteRoutedEventArgs e){ PaneToolWindow tw = sender as PaneToolWindow; XamDockManager dm = XamDockManager.GetDockManager(tw); if (dm != null) { RoutedCommand rc = e.Command as RoutedCommand; if (null != rc) { // if the CanExecute reaches the ToolWindow then nothing has // handled it. we'll delegate the canexecute call to the dockmanager // and let it bubble up from there e.CanExecute = rc.CanExecute(e.Parameter, dm); e.ContinueRouting = false; e.Handled = true; } }} private static void OnToolWindowExecuteCommand(object sender, ExecutedRoutedEventArgs e){ PaneToolWindow tw = sender as PaneToolWindow; XamDockManager dm = XamDockManager.GetDockManager(tw); if (dm != null) { RoutedCommand rc = e.Command as RoutedCommand; if (null != rc) { // if the Execute reaches the ToolWindow then nothing has // handled it. we'll delegate the canexecute call to the dockmanager // and let it bubble up from there rc.Execute(e.Parameter, dm); e.Handled = true; } }} private void OnToolWindowLoaded(object sender, PaneToolWindowEventArgs e){ e.Window.AddHandler(CommandManager.CanExecuteEvent, new CanExecuteRoutedEventHandler(OnToolWindowCanExecuteCommand)); e.Window.AddHandler(CommandManager.ExecutedEvent, new ExecutedRoutedEventHandler(OnToolWindowExecuteCommand));}
if (dm != null) { RoutedCommand rc = e.Command as RoutedCommand;
if (null != rc) { // if the CanExecute reaches the ToolWindow then nothing has // handled it. we'll delegate the canexecute call to the dockmanager // and let it bubble up from there e.CanExecute = rc.CanExecute(e.Parameter, dm); e.ContinueRouting = false; e.Handled = true; } }}
private static void OnToolWindowExecuteCommand(object sender, ExecutedRoutedEventArgs e){ PaneToolWindow tw = sender as PaneToolWindow; XamDockManager dm = XamDockManager.GetDockManager(tw);
if (null != rc) { // if the Execute reaches the ToolWindow then nothing has // handled it. we'll delegate the canexecute call to the dockmanager // and let it bubble up from there rc.Execute(e.Parameter, dm); e.Handled = true; } }}
private void OnToolWindowLoaded(object sender, PaneToolWindowEventArgs e){ e.Window.AddHandler(CommandManager.CanExecuteEvent, new CanExecuteRoutedEventHandler(OnToolWindowCanExecuteCommand)); e.Window.AddHandler(CommandManager.ExecutedEvent, new ExecutedRoutedEventHandler(OnToolWindowExecuteCommand));}