12

My drop event

private void Window_Drop(object sender, DragEventArgs e)
{
    var window = e.Data.GetData(typeof(Window)) as Window;
    if (window != null)
    {
        var tabitem = new TabItem();
        tabitem.Content = window.Content;
        tabcontrol1.Items.Add(tabitem);
        window.Close();
    }
}

My mainwindow XAML

 <Window x:Class="WpfApplication2.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="MainWindow" Height="350" Width="525" Drop="Window_Drop">

Nothing happens, any idea why?

How can I drop any window in my application into my main window?

to demonstrate what i am trying to do enter image description here the tabitem5 and tabitem2 were dragged outside the mainwindow and thus the became independent windows, now i am trying to reverse the process and make them tabs again by dragging them to the main window

i am giving the bounty for a full code sample, tab to window and window to tab, an mvvm solution is acceptable too

FPGA
  • 3,525
  • 10
  • 44
  • 73
  • please post your full code including the code that's starting the drag operation. – Federico Berasategui Oct 25 '13 at 17:05
  • @HighCore thats what i am missing then – FPGA Oct 25 '13 at 17:07
  • @HighCore PreviewMouseMove handler should be on the sub window that i want to drag? – FPGA Oct 25 '13 at 17:08
  • Have you put a breakpoint in your function? Does it ever reach the function? – gunr2171 Oct 25 '13 at 17:09
  • 1
    @gunr2171 it never does, if i create another window and drop it on the main window nothing happens, how ever it does get there when i drop somthing from inside the main window, but since its not a window nothing happens which is what i want in that case – FPGA Oct 25 '13 at 17:11
  • Are you trying to initiate drag drop using the title bar of a Window? – Andy Oct 25 '13 at 17:18
  • @Andy exactly, then when a window is dropped into main window, i want to convert it to tabitem and close it, and i am not sure what events i need to handle on my other window – FPGA Oct 25 '13 at 17:19
  • What event/method are you using to try and detect the dragdrop starting? you don't get mouse moves or anything when you drag the title bar. – Andy Oct 25 '13 at 17:57
  • and why was this downvoted? seems legit to me – Andy Oct 25 '13 at 17:57
  • @Andy as i said i am not sure what events i have to detect when i drag the window that i want to drop, i am trying to create somthing like chrome, it works from tabitem to windoww, but not the other way around – FPGA Oct 25 '13 at 18:17
  • @Andy please check my edit to get the idea – FPGA Oct 25 '13 at 18:48
  • How are you initiating the drag and drop? Are you using the standard drag and drop methods? I.E. DataObject dataObject = new DataObject(dataFormat, files); DragDrop.DoDragDrop(this.FileView, dataObject, DragDropEffects.Copy); – Paul Wade Oct 30 '13 at 16:02
  • I think for dropping a window into another you will need to implement a custom drag and drop maybe using mouse over events and figuring out the last clicked window when something gets pulled over main. – Paul Wade Oct 30 '13 at 16:03
  • Can you put breakpoint on `e.Data` and see what type of data is available? – Akash Kava Oct 31 '13 at 07:23

1 Answers1

8

It sounds like you are trying to implement a docking system. Have you had a look at existing Docking Managers.

Avalon Dock is a great Open Source example. It's well documented and easy to use.

If you're determined to implement your own, you can try to find if there is a Window beneath the one you are dragging. Unfortunately WPF doesn't have an easy way to HitTest across Windows. The way around this would be to make some Win32 calls. The code used is from another SO thread here, by Ray Burns and a Win32 call for getting the current mouse position, by Fredrik Hedblad.

I've also used WindowStyle="None" and implemented a custom title bar for the window so I can catch mouse events on the window.

I'm not entirely sure how you have implemented the tab dragging to create a new window but if that is working you can do the following.

XAML

<Window x:Class="WpfApplication1.DraggedWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Dragged Window" Height="350" Width="525"
    MouseMove="DraggedWindow_OnMouseMove" MouseDown="DraggedWindow_OnMouseDown" MouseUp="DraggedWindow_OnMouseUp" WindowStyle="None">
<Window.Resources>
    <Style TargetType="HeaderedContentControl">
        <Setter Property="HeaderTemplate">
            <Setter.Value>
                <DataTemplate>
                    <Border Background="Gray" Opacity="0.8">
                        <DockPanel LastChildFill="True">
                            <Button DockPanel.Dock="Right" Content="X" Width="20" Height="20" Margin="2"/>
                            <TextBlock DockPanel.Dock="Left" Text="{Binding Header}"/>
                        </DockPanel>
                    </Border>
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <HeaderedContentControl Header="{Binding}" Content="{Binding Content}"/>
</Grid>

Code

public partial class DraggedWindow : Window
{
    private readonly MainWindow _mainWindow;
    private bool _isDropped = false;

    public DraggedWindow(MainWindow mainWindow)
    {
        _mainWindow = mainWindow;
        InitializeComponent();
        DataContext = new TabItem() { Header = "TabItem6", Content = "Content6" };
    }

    const uint GW_HWNDNEXT = 2;

    [DllImport("User32")]
    static extern IntPtr GetTopWindow(IntPtr hWnd);
    [DllImport("User32")]
    static extern IntPtr GetWindow(IntPtr hWnd, uint wCmd);
    [DllImport("User32")]
    [return: MarshalAs(UnmanagedType.Bool)]
    internal static extern bool GetCursorPos(ref Win32Point pt);

    [StructLayout(LayoutKind.Sequential)]
    internal struct Win32Point
    {
        public Int32 X;
        public Int32 Y;
    };

    public static Point GetMousePosition()
    {
        Win32Point w32Mouse = new Win32Point();
        GetCursorPos(ref w32Mouse);
        return new Point(w32Mouse.X, w32Mouse.Y);
    }

    public Window FindWindowUnderThisAt(Point screenPoint)  // WPF units (96dpi), not device units
    {
        return (
          from win in SortWindowsTopToBottom(Application.Current.Windows.OfType<Window>())
          where new Rect(win.Left, win.Top, win.Width, win.Height).Contains(screenPoint)
          && !Equals(win, this)
          select win
        ).FirstOrDefault();
    }

    public IEnumerable<Window> SortWindowsTopToBottom(IEnumerable<Window> unsorted)
    {
        var byHandle = unsorted.ToDictionary(win =>
            ((HwndSource)PresentationSource.FromVisual(win)).Handle);

        for (IntPtr hWnd = GetTopWindow(IntPtr.Zero); hWnd != IntPtr.Zero; hWnd = GetWindow(hWnd, GW_HWNDNEXT))
        {
            if (byHandle.ContainsKey(hWnd))
                yield return byHandle[hWnd];
        }
    }

    private void DraggedWindow_OnMouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            this.DragMove();
        }

        var absoluteScreenPos = GetMousePosition();
        var windowUnder = FindWindowUnderThisAt(absoluteScreenPos);
        if (windowUnder != null && windowUnder.Equals(_mainWindow))
        {
            if (_isDropped)
            {
                // Your code here
                var tabitem = new TabItem();
                tabitem.Content = (DataContext as TabItem).Content;
                tabitem.Header = (DataContext as TabItem).Header;
                _mainWindow.TabControl1.Items.Add(tabitem);
                this.Close();
            }
        }
    }

    private void DraggedWindow_OnMouseDown(object sender, MouseButtonEventArgs e)
    {
        _isDropped = false;
    }

    private void DraggedWindow_OnMouseUp(object sender, MouseButtonEventArgs e)
    {
        _isDropped = true;
    }
}

Main Window Xaml (example)

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="350" Width="525">
<Grid>
    <TabControl Name="TabControl1">
        <TabItem Header="TabItem1">Content1</TabItem>
        <TabItem Header="TabItem2">Content2</TabItem>
        <TabItem Header="TabItem3">Content3</TabItem>
        <TabItem Header="TabItem4">Content4</TabItem>
        <TabItem Header="TabItem5">Content5</TabItem>
    </TabControl>
</Grid>

Main Window Code (example)

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        new DraggedWindow(this).Show();
    }
}
Community
  • 1
  • 1
nickm
  • 1,775
  • 1
  • 12
  • 14
  • 1
    just perfect, the thing is with the available dock managers they don't support converting the dock item to a seperate window, i want to see my dock items in the task bar and i dont want them to minimize when i minimize the application, +185, and i wish i could give you more – FPGA Oct 31 '13 at 07:49