brzmi jak próbujesz wprowadzić system dokowania. Czy spojrzałeś na obecnych kierowników dokowania?
Avalon Dock to świetny przykład Open Source. Jest dobrze udokumentowany i łatwy w użyciu.
Jeśli chcesz wdrożyć własne, możesz spróbować sprawdzić, czy pod tym, co przeciągasz znajduje się okno. Niestety, WPF nie ma łatwego sposobu na trafienie HitTest przez Windows. Sposób obejścia tego spowoduje wykonanie niektórych wywołań Win32. Używany kod pochodzi z innego wątku SO here, przez Ray Burns i wywołania Win32 dla uzyskania bieżącego mouse position, przez Fredrik Hedblad.
Użyłem również WindowStyle="None"
i zaimplementowałem niestandardowy pasek tytułu okna, dzięki czemu mogę uchwycić zdarzenia myszy w oknie.
Nie jestem do końca pewien, w jaki sposób zaimplementowano przeciąganie karty w celu utworzenia nowego okna, ale jeśli to działa, można wykonać następujące czynności.
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>
Kod
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;
}
}
Okno główne Xaml (przykład)
<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>
główny kod okno (przykład)
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
new DraggedWindow(this).Show();
}
}
proszę umieszczać swój pełny kod wraz z numerem, który zaczyna operację przeciągania. –
@HighCore to, czego mi brakuje, to – FPGA
@HighCore PreviewMouseMove handler powinien być w oknie podrzędnym, które chcę przeciągnąć? – FPGA