@@ -16,14 +16,11 @@ namespace Demo
1616 /// <summary>
1717 /// Interaction logic for MainWindow.xaml
1818 /// </summary>
19- public partial class MainWindow : Window
19+ public partial class MainWindow : WindowBase
2020 {
21- //We use this collection to keep track of what windows we have open
22- private List < DockingWindow > _openWindows ;
2321 public MainWindow ( )
2422 {
2523 InitializeComponent ( ) ;
26- _openWindows = new List < DockingWindow > ( ) ;
2724 }
2825
2926 /// <summary>
@@ -32,170 +29,36 @@ public MainWindow()
3229 /// </summary>
3330 /// <param name="sender"></param>
3431 /// <param name="e"></param>
35- private void ChromeTabControl_TabDraggedOutsideBonds ( object sender , TabDragEventArgs e )
32+ private void TabControl_TabDraggedOutsideBonds ( object sender , TabDragEventArgs e )
3633 {
3734 TabBase draggedTab = e . Tab as TabBase ;
38- if ( draggedTab is TabClass3 )
39- return ; //As an example, we don't want out TabClass3 to form new windows, so we stop it here.
40- DockingWindow win = _openWindows . FirstOrDefault ( x => x . DataContext == draggedTab ) ; //check if it's already open
41-
42- if ( win == null ) //If not, create a new one
43- {
44- win = new DockingWindow
45- {
46- Title = draggedTab ? . TabName ,
47- DataContext = draggedTab
48- } ;
49-
50- win . Closed += win_Closed ;
51- win . Loaded += win_Loaded ;
52- win . LocationChanged += win_LocationChanged ;
53- win . Tag = e . CursorPosition ;
54- win . Left = e . CursorPosition . X - win . Width + 200 ;
55- win . Top = e . CursorPosition . Y - 20 ;
56- win . Show ( ) ;
57- }
58- else
35+ if ( TryDragTabToWindow ( e . CursorPosition , draggedTab ) )
5936 {
60- Debug . WriteLine ( DateTime . Now . ToShortTimeString ( ) + " got window" ) ;
61- MoveWindow ( win , e . CursorPosition ) ;
37+ //Set Handled to true to tell the tab control that we have dragged the tab to a window, and the tab should be closed.
38+ e . Handled = true ;
6239 }
63- _openWindows . Add ( win ) ;
64- //Set Handled to true to tell the tab control that we have dragged the tab to a window, and the tab should be closed.
65- e . Handled = true ;
66- }
67-
68- private void win_Loaded ( object sender , RoutedEventArgs e )
69- {
70- Window win = ( Window ) sender ;
71- win . Loaded -= win_Loaded ;
72- Point cursorPosition = ( Point ) win . Tag ;
73- MoveWindow ( win , cursorPosition ) ;
7440 }
75- private void MoveWindow ( Window win , Point pt )
76- {
77- //Use a BeginInvoke to delay the execution slightly, else we can have problems grabbing the newly opened window.
78- Dispatcher . BeginInvoke ( new Action ( ( ) =>
79- {
80- win . Topmost = true ;
81- //We position the window at the mouse position
82- win . Left = pt . X - win . Width + 200 ;
83- win . Top = pt . Y - 20 ;
84- Debug . WriteLine ( DateTime . Now . ToShortTimeString ( ) + " dragging window" ) ;
85-
86- if ( Mouse . LeftButton == MouseButtonState . Pressed )
87- {
88- win . DragMove ( ) ; //capture the movement to the mouse, so it can be dragged around
89- }
9041
91- win . Topmost = false ;
92- } ) ) ;
93- }
94- //remove the window from the open windows collection when it is closed.
95- private void win_Closed ( object sender , EventArgs e )
96- {
97- _openWindows . Remove ( sender as DockingWindow ) ;
98- Debug . WriteLine ( DateTime . Now . ToShortTimeString ( ) + " closed window" ) ;
99- }
100- //We use this to keep track of where the window is on the screen, so we can dock it later
101- private void win_LocationChanged ( object sender , EventArgs e )
42+ protected override bool TryDockWindow ( Point position , TabBase dockedWindowVM )
10243 {
103- Window win = ( Window ) sender ;
104- if ( ! win . IsLoaded )
105- return ;
106- W32Point pt = new W32Point ( ) ;
107- if ( ! Win32 . GetCursorPos ( ref pt ) )
108- {
109- Marshal . ThrowExceptionForHR ( Marshal . GetHRForLastWin32Error ( ) ) ;
110- }
111-
112- Point absoluteScreenPos = new Point ( pt . X , pt . Y ) ;
113-
114- var windowUnder = FindWindowUnderThisAt ( win , absoluteScreenPos ) ;
115-
116- if ( windowUnder != null && windowUnder . Equals ( this ) )
44+ //Hit test against the tab control
45+ if ( MyChromeTabControl . InputHitTest ( position ) is FrameworkElement element )
11746 {
118- Point relativePoint = PointFromScreen ( absoluteScreenPos ) ; //The screen position relative to the main window
119- FrameworkElement element = MyChromeTabControl . InputHitTest ( relativePoint ) as FrameworkElement ; //Hit test against the tab control
120-
121- if ( element != null )
47+ ////test if the mouse is over the tab panel or a tab item.
48+ if ( CanInsertTabItem ( element ) )
12249 {
123- ////test if the mouse is over the tab panel or a tab item.
124- if ( CanInsertTabItem ( element ) )
125- {
126- TabBase dockedWindowVM = ( TabBase ) win . DataContext ;
127- ViewModelMainWindow mainWindowVm = ( ViewModelMainWindow ) DataContext ;
128-
129- mainWindowVm . ItemCollection . Add ( dockedWindowVM ) ;
130-
131- win . Close ( ) ;
132-
133- mainWindowVm . SelectedTab = dockedWindowVM ;
134-
135- //We run this method on the tab control for it to grab the tab and position it at the mouse, ready to move again.
136- MyChromeTabControl . GrabTab ( dockedWindowVM ) ;
137-
138- }
139- }
140- }
141- }
142-
143- private bool CanInsertTabItem ( FrameworkElement element )
144- {
145- if ( element is ChromeTabItem )
146- return true ;
147- if ( element is ChromeTabPanel )
148- return true ;
149- object child = LogicalTreeHelper . GetChildren ( element ) . Cast < object > ( ) . FirstOrDefault ( x => x is ChromeTabPanel ) ;
150- if ( child != null )
151- return true ;
152- FrameworkElement localElement = element ;
153- while ( true )
154- {
155- Object obj = localElement ? . TemplatedParent ;
156- if ( obj == null )
157- break ;
158-
159- if ( obj is ChromeTabItem )
50+ //TabBase dockedWindowVM = (TabBase)win.DataContext;
51+ ViewModelExampleBase vm = ( ViewModelExampleBase ) DataContext ;
52+ vm . ItemCollection . Add ( dockedWindowVM ) ;
53+ vm . SelectedTab = dockedWindowVM ;
54+ //We run this method on the tab control for it to grab the tab and position it at the mouse, ready to move again.
55+ MyChromeTabControl . GrabTab ( dockedWindowVM ) ;
16056 return true ;
161- localElement = localElement . TemplatedParent as FrameworkElement ;
57+ }
16258 }
16359 return false ;
16460 }
16561
166- /// <summary>
167- /// Used P/Invoke to find and return the top window under the cursor position
168- /// </summary>
169- /// <param name="source"></param>
170- /// <param name="screenPoint"></param>
171- /// <returns></returns>
172- private Window FindWindowUnderThisAt ( Window source , Point screenPoint ) // WPF units (96dpi), not device units
173- {
174- var allWindows = SortWindowsTopToBottom ( Application . Current . Windows . OfType < Window > ( ) ) ;
175- var windowsUnderCurrent = from win in allWindows
176- where ( win . WindowState == WindowState . Maximized || new Rect ( win . Left , win . Top , win . Width , win . Height ) . Contains ( screenPoint ) )
177- && ! Equals ( win , source )
178- select win ;
179- return windowsUnderCurrent . FirstOrDefault ( ) ;
180- }
181-
182- /// <summary>
183- /// We need to do some P/Invoke magic to get the windows on screen
184- /// </summary>
185- /// <param name="unsorted"></param>
186- /// <returns></returns>
187- private IEnumerable < Window > SortWindowsTopToBottom ( IEnumerable < Window > unsorted )
188- {
189- var byHandle = unsorted . ToDictionary ( win =>
190- ( ( HwndSource ) FromVisual ( win ) ) . Handle ) ;
191-
192- for ( IntPtr hWnd = Win32 . GetTopWindow ( IntPtr . Zero ) ; hWnd != IntPtr . Zero ; hWnd = Win32 . GetWindow ( hWnd , Win32 . GW_HWNDNEXT ) )
193- {
194- if ( byHandle . ContainsKey ( hWnd ) )
195- yield return byHandle [ hWnd ] ;
196- }
197- }
198-
19962 private void BnOpenPinnedTabExample_Click ( object sender , RoutedEventArgs e )
20063 {
20164 new PinnedTabExampleWindow ( ) . Show ( ) ;
0 commit comments