We are trying to make a robust WPF application where we have several add-in in separate exe's. We can load them into the main window of the application but we would really like to be able to load the exe's into multiple tabs.
Doable? If so how?
Actually we are trying to do something like this: https://msdn.microsoft.com/en-us/magazine/dn519924.aspx but where as they are using a regular tab we would want to use the docking and probably put each out of process object in a content pane tab.
I'll just expand a bit on what Tacho said. Basically the sample you are referring to is using WPF addins which ultimately just host the view in an AddInHost (an internal HwndHost derived class in the System.Windows.Presentation assembly). The xamDockManager can contain HwndHost derived elements just like they can be hosted in any other element and just as they are hosted in the tabcontrol in that sample. If you're question is more about how to in an MVVM way define content for contentpanes then perhaps you would look at Brian's blog post here.
Note, HwndHosts are separate hwnds and as such will mean air space issues in WPF as described here in the context of WindowsFormsHost (which is just another type of hwndHost). The xamDockManager will act a little differently when you are using hwndhosts - e.g. the unpinned flyout will be displayed in a popup to ensure the content is above any hwndhosts, animations of unpinned panes that contain an hwndhost will be disabled, etc.
Thx Andrew.
When I bind the ItemsSource property of the TabGroupPane to the LoadedPlugins property in the ViewModel from the previously mentioned MSDN article I get the following error:
Error loading plugin. InvalidOperationException: A TabGroupPane can only contain 'ContentPane' and 'ContentPanePlaceholder' instances. etc etc.
Any ideas how to get a round this? The LoadedPlugins property is returning a Collection of Plugin objects which kinda hints at Tacho's response that it is not supported.
That is correct. You cannot use the ItemsSource because the ItemsSource of an ItemsControl will automatically create an element for each data item and add it to the associated ItemsPanel. The xamDockManager needs to be able to remove a pane from the current location in order to allow moving it elsewhere, unpinning it, etc. You would need to either create the ContentPanes in xaml, create them programmatically or use a behavior like the article that I mentioned in my previous reply.
I don't know what you mean by making tabs tile. If you mean having it create multiple ContentPanes within a SplitPane in which case those are not tabs and no, Brian's behavior wouldn't do that. You would need to write your own custom attached behavior. You could try commenting on his blog post - maybe he has something like that already but I doubt it given that the post is about his "TabGroupPaneItemsSourceBehavior".
This works great. Thanks
Just one more question...
With the TabGroup is there a method/property to have the tabs tile. I know you can do this my manually dragging the tabs but it would be nice if there was some way for, say 4 tabs, to tile automatically.
I don't know that I can redistribute that article's source so I won't repost a modified version of that sample but the steps would be:
e.g. Define the property
<code>
public static readonly DependencyProperty ClosedCommandProperty = DependencyProperty.Register("ClosedCommand", typeof(System.Windows.Input.ICommand), typeof(TabGroupPaneItemsSourceBehavior));
public System.Windows.Input.ICommand ClosedCommand{ get { return (System.Windows.Input.ICommand)GetValue(ClosedCommandProperty); } set { SetValue(ClosedCommandProperty, value); }}
</code>
And modify add the part to use it.
e.g.
private void Container_Closed(object sender, PaneClosedEventArgs e){ ContentPane contentPane = sender as ContentPane; if (contentPane != null) { contentPane.Closed -= Container_Closed; //no memory leaks
var item = contentPane.DataContext;
if (ItemsSource != null && ItemsSource.Contains(item)) ItemsSource.Remove(item);
RemoveBindings(contentPane);
if (null != this.ClosedCommand) this.ClosedCommand.Execute(item); }}
I've attached a modified version of Brian's file which has these two changes.
Then you just add something like the following in place of the TabControl in the MainWindow.xaml:
<igWpf:XamDockManager x:Name="dockManager" xmlns:igWpf="http://schemas.infragistics.com/xaml/wpf" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:dockMvvm="clr-namespace:XamDockManager_MVVM"> <igWpf:XamDockManager.Panes> <igWpf:SplitPane> <igWpf:TabGroupPane x:Name="plugins"> <i:Interaction.Behaviors> <dockMvvm:TabGroupPaneItemsSourceBehavior ClosedCommand="{Binding DataContext.CloseTabCommand, ElementName=dockManager}" HeaderMemberPath="Title" ItemsSource="{Binding LoadedPlugins}"> <dockMvvm:TabGroupPaneItemsSourceBehavior.ItemTemplate> <DataTemplate > <ContentPresenter Content="{Binding View}" /> </DataTemplate> </dockMvvm:TabGroupPaneItemsSourceBehavior.ItemTemplate> </dockMvvm:TabGroupPaneItemsSourceBehavior> </i:Interaction.Behaviors> </igWpf:TabGroupPane> </igWpf:SplitPane> </igWpf:XamDockManager.Panes> </igWpf:XamDockManager>
Boy sorry for being so dense but can you show me how you can bind a contentpane to the "SelectedPlugin" property in the ViewModel in the MSDN article.
SelectedPlugIn is returning a Plugin Object which you say (above in this thread) is a HwndHost.