If I have more than one XamDockManager in an application, it appears that ContentPane instances within each XamDockManager may not be dragged into another XamDockManager. Is it possible to make it so that they can?
I came up with a way to do the full drag and drop from one XamDockManager to another. It's a little bit of a kludge, but it seems to work pretty well:
public partial class App : Application
{
List<MainWindow> mainWindows = new List<MainWindow>();
protected override void OnStartup(StartupEventArgs e)
this.mainWindows.Add(CreateMainWindow());
}
private MainWindow CreateMainWindow()
MainWindow mainWindow;
mainWindow = new MainWindow();
mainWindow.PaneDragStarting += new EventHandler<PaneDragStartingEventArgs>(paneDragStarting);
mainWindow.PaneDragEnded += new EventHandler<PaneDragEndedEventArgs>(paneDragEnded);
mainWindow.MouseMove += new System.Windows.Input.MouseEventHandler(mouseMove);
mainWindow.Show();
return mainWindow;
ContentPane[] draggedPanes = null;
void paneDragStarting(object sender, Infragistics.Windows.DockManager.Events.PaneDragStartingEventArgs e)
this.draggedPanes = e.Panes.ToArray();
void paneDragEnded(object sender, PaneDragEndedEventArgs e)
this.draggedPanes = null;
[DllImport("user32.dll")]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
private const int WM_LBUTTONDOWN = 0x201;
private const int WM_LBUTTONUP = 0x202;
private const int MK_LBUTTON = 0x01;
private const int WM_NCLBUTTONDOWN = 0x00a1;
private const int HTCAPTION = 2;
private IntPtr MakePointStruct(Point point)
IntPtr ptr = (IntPtr) ( ((int) point.X) + (((int) point.Y) << 16 ) );
return ptr;
void mouseMove(object sender, System.Windows.Input.MouseEventArgs e)
MainWindow sourceWindow = sender as MainWindow;
foreach (MainWindow destWindow in this.mainWindows)
if (destWindow == sourceWindow)
continue;
Point pt = e.GetPosition(destWindow);
if (this.draggedPanes != null && destWindow.InputHitTest(pt) != null)
ContentPane[] panes = draggedPanes;
SendMessage(new WindowInteropHelper(sourceWindow).Handle, WM_LBUTTONUP, (IntPtr)0, MakePointStruct(e.GetPosition(sourceWindow)));
MovePanesToDockManager(panes, destWindow.xamDockManager1);
Window parent = Window.GetWindow(panes[0]);
parent.Activate();
SendMessage(new WindowInteropHelper(parent).Handle, WM_NCLBUTTONDOWN, (IntPtr)HTCAPTION, MakePointStruct(parent.PointToScreen(e.GetPosition(parent))));
break;
internal void MovePanesToDockManager(ContentPane[] panes, XamDockManager dockManager)
double top = parent.Top;
double left = parent.Left;
double width = parent.Width;
double height = parent.Height;
bool isTabGroup = false;
foreach (ContentPane pane in panes)
if (pane.Parent is SplitPane)
((SplitPane)(pane.Parent)).Panes.Remove(pane);
else if (pane.Parent is TabGroupPane)
((TabGroupPane)(pane.Parent)).Items.Remove(pane);
isTabGroup = true;
else if (pane.Parent is UnpinnedTabArea)
return;
SplitPane splitPane = new SplitPane();
splitPane.SetValue(XamDockManager.InitialLocationProperty, InitialPaneLocation.DockableFloating);
if (isTabGroup)
TabGroupPane tabGroupPane = new TabGroupPane();
tabGroupPane.Items.Add(pane);
splitPane.Panes.Add(tabGroupPane);
else
splitPane.Panes.AddRange(panes);
dockManager.Panes.Add(splitPane);
parent = Window.GetWindow(splitPane);
parent.Top = top;
parent.Left = left;
parent.Width = width;
parent.Height = height;
Thanks @dmackersie for posting your solutions. I had the same requirement. I used part of your work to solve the problem for our team. This is what worked for my situation.
I added an event to the XamDockManager, PaneDragOver="DockManager_OnPaneDragOver"
/// <summary> /// use this event to re-assign the controlling dock manager when a pane enters. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void DockManager_OnPaneDragOver(object sender, PaneDragOverEventArgs e) {
if (e.Panes.Count == 1) {
SplitPane split = e.Panes[0].Parent as SplitPane; //this excludes the tabgroups. if (split == null) { return; }
//check to see if this dockmanager already contains the panel if (((XamDockManager)sender).Panes.Contains(split)) { return; }
//sender belongs to the dockmanager dragged over, it's not the one this pane belongs to so change the ownership ((MainWindowViewModel)DataContext).MovePanesToDockManager(e.Panes.ToArray(), sender as XamDockManager);
} }
///////////////////////////////////////////////////////////////// #region move panes between dockmanagers
public void MovePanesToDockManager(ContentPane[] panes, XamDockManager dockManager) { bool isTabGroup = false;
foreach (ContentPane pane in panes) { if (pane.Parent is SplitPane) { ((SplitPane)(pane.Parent)).Panes.Remove(pane); } else if (pane.Parent is TabGroupPane) { ((TabGroupPane)(pane.Parent)).Items.Remove(pane); isTabGroup = true; } else if (pane.Parent is UnpinnedTabArea) { return; } }
SplitPane splitPane = new SplitPane(); splitPane.SetValue(XamDockManager.InitialLocationProperty, InitialPaneLocation.DockableFloating); if (isTabGroup) { TabGroupPane tabGroupPane = new TabGroupPane(); foreach (ContentPane pane in panes) { tabGroupPane.Items.Add(pane); } splitPane.Panes.Add(tabGroupPane); } else { splitPane.Panes.AddRange(panes); }
#endregion