Drop a window into another window

2019-02-21 11:34发布

问题:

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 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

回答1:

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();
    }
}


标签: c# wpf window