Commands not passed to floating ToolWindow

Docking/MDI for WPF Forum

Posted 8 years ago by Jb RIGUET
Version: 11.2.0554
Platform: .NET 4.0
Environment: Windows 7 (64-bit)
Avatar

Hi,

I'm encountering a small (but quite problematic) issue with the Docking component.

When I add a CommandBinding to a UserControl, hosted in a simple ToolWindow, there is no problem when the ToolWindow is docked into the MainWindow (which use a Ribbon), but when I make it float, on my second screen, Commands CanExecute Methods are not evaluated, and therefore, never activated.

Is there anything known aabout this issue ? Is it a bug, or are you able to guide me to a workaround ?

Thanks !

Comments (5)

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

Hi,

When you float the docking window (not to be confused with WPF's Window class), it is hosted in a separate WPF Window.  Routed commands and key combinations will not route up to your main app Window. This is a standard behavior of WPF when dealing with multiple Window objects.

To work around there, there are several options:

You can either register a class handler/input binding for the Window type, or you'd have to add bindings to each RaftingWindow.  RaftingWindow is our class that inherits the WPF Window and is used to host any floating docking window controls.  The latter method can be done using an attached behavior and an implicit Style for the RaftingWindow type.  Or you can override the DockSite.CreateRaftingWindow method and add your bindings there.

The other option is to use some app frameworks like Prism that use delegate commands instead of routed commands.  Those kinds of frameworks and commands track activation across Window boundaries better, but they can be more time-consuming to get up and running in.

I hope that helps!


Actipro Software Support

Posted 8 years ago by Jb RIGUET
Avatar

Thanks, I was aware it would be a standard WPF behavior, but the workarounds you gave me should be enough to make it work like I want.

Thanks a lot !

Posted 3 years ago by Miles Merckel
Avatar

Hi

 

This is the issue I am having. I understand what you are saying to workaround it but have no idea how to implement it. There appears to be no examples in the the demo or explanation in the documentation.

 

Is it possible to provide a brief code snippet to assit?

 

Many Thanks

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

Hi Miles,

Yes, here's a very small example that works with v2016.1.  XAML for a MainControl:

<Grid>
	<Grid.RowDefinitions>
		<RowDefinition Height="Auto" />
		<RowDefinition Height="*" />
	</Grid.RowDefinitions>

	<ToolBar DockPanel.Dock="Top">
		<Button Content="Open" Command="Open" />
	</ToolBar>

	<!-- DockSite -->
	<sample:CustomDockSite x:Name="dockSite" Grid.Row="1">
		<docking:SplitContainer>
			<docking:Workspace>
				<docking:TabbedMdiHost />
			</docking:Workspace>

			<docking:ToolWindowContainer>
				<docking:ToolWindow Title="Solution Explorer">
					<DockPanel>
						<ToolBar DockPanel.Dock="Top">
							<Button Content="Open" Command="Open" />
						</ToolBar>
						<TextBox BorderThickness="0" />
					</DockPanel>
				</docking:ToolWindow>
			</docking:ToolWindowContainer>
		</docking:SplitContainer>
	</sample:CustomDockSite>

</Grid>

Code-behind for MainControl:

public partial class MainControl {

	public MainControl() {
		InitializeComponent();

		this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, OnOpenCommandExecuted));
	}

	private void OnOpenCommandExecuted(object sender, ExecutedRoutedEventArgs e) {
		MessageBox.Show("Open dialog here");
	}

}

CustomDockSite class:

public class CustomDockSite : DockSite {

	private void CopyCommandBindings(UIElement source, Window target) {
		if ((source != null) && (target != null)) {
			foreach (CommandBinding binding in source.CommandBindings)
				target.CommandBindings.Add(binding);
		}
	}

	protected override void InitializeFloatingWindow(Window window) {
		base.InitializeFloatingWindow(window);

		// Get the ancestor control with all the command bindings
		var bindingSource = VisualTreeHelperExtended.GetAncestor<MainControl>(this);

		// Copy the bindings to the new Window
		this.CopyCommandBindings(bindingSource, window);
	}

}

The MainControl is where we define all our routed command bindings.  In your app, you might need to adjust that logic or even the CopyCommandBindings logic as appropriate to suit your needs.

If you are using v2015.1 or older, you would need to replace InitializeFloatingWindow with CreateRaftingWindow, call the base method to get the Window that is created and pass that to the CopyCommandBindings method.


Actipro Software Support

Posted 3 years ago by Miles Merckel
Avatar

Hi

Thanks for the reply much appreciated. I managed to get it working with a few changes as I'm using 2015.1, here's the updated snippet for 2015.1

public class CustomDockSite : DockSite
{
    private void CopyCommandBindings(UIElement source, RaftingHost target)
    {
        if ((source != null) && (target != null))
        {
            foreach (CommandBinding binding in source.CommandBindings)
                target.CommandBindings.Add(binding);
        }
    }

    protected override IRaftingWindow CreateRaftingWindow(RaftingHost window)
    {
        var obj = base.CreateRaftingWindow(window);

        // Get the ancestor control with all the command bindings
        var bindingSource = VisualTreeHelperExtended.GetAncestor<Window>(this);

        // Copy the bindings to the new Window
        CopyCommandBindings(bindingSource, window);

        return obj;
    }
}

 Many Thanks

The latest build of this product (v2019.1 build 0683) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.