Skip to content

Commit 4671f27

Browse files
committed
Updated demo project
1 parent ac736b0 commit 4671f27

File tree

8 files changed

+271
-164
lines changed

8 files changed

+271
-164
lines changed

Demo/CustomStyleExampleWindow.xaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Window x:Class="Demo.CustomStyleExampleWindow"
1+
<local:WindowBase x:Class="Demo.CustomStyleExampleWindow"
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
@@ -320,6 +320,7 @@
320320
MinimumTabWidth="40"
321321
PinnedTabWidth="50"
322322
MaximumTabWidth="250"
323+
TabDraggedOutsideBonds="TabControl_TabDraggedOutsideBonds"
323324
ItemContainerStyle="{StaticResource CustomTabItemStyle}">
324325
<!--We override the control template here to show how you can modify the properties of tab panel and content presenter-->
325326
<ct:ChromeTabControl.Template>
@@ -368,4 +369,4 @@
368369
</ct:ChromeTabControl.AddButtonTemplate>
369370
</ct:ChromeTabControl>
370371
</Grid>
371-
</Window>
372+
</local:WindowBase>
Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,47 @@
1-
using System.Windows;
1+
using ChromeTabs;
2+
using Demo.ViewModel;
3+
using System.Windows;
24

35
namespace Demo
46
{
57
/// <summary>
68
/// Interaction logic for CustomStyleExampleWindow.xaml
79
/// </summary>
8-
public partial class CustomStyleExampleWindow : Window
10+
public partial class CustomStyleExampleWindow : WindowBase
911
{
1012
public CustomStyleExampleWindow()
1113
{
1214
InitializeComponent();
1315
}
16+
17+
private void TabControl_TabDraggedOutsideBonds(object sender, TabDragEventArgs e)
18+
{
19+
TabBase draggedTab = e.Tab as TabBase;
20+
if (TryDragTabToWindow(e.CursorPosition, draggedTab))
21+
{
22+
//Set Handled to true to tell the tab control that we have dragged the tab to a window, and the tab should be closed.
23+
e.Handled = true;
24+
}
25+
}
26+
27+
protected override bool TryDockWindow(Point position, TabBase dockedWindowVM)
28+
{
29+
//Hit test against the tab control
30+
if (MyChromeTabControlWithCustomStyle.InputHitTest(position) is FrameworkElement element)
31+
{
32+
////test if the mouse is over the tab panel or a tab item.
33+
if (CanInsertTabItem(element))
34+
{
35+
//TabBase dockedWindowVM = (TabBase)win.DataContext;
36+
ViewModelExampleBase vm = (ViewModelExampleBase)DataContext;
37+
vm.ItemCollection.Add(dockedWindowVM);
38+
vm.SelectedTab = dockedWindowVM;
39+
//We run this method on the tab control for it to grab the tab and position it at the mouse, ready to move again.
40+
MyChromeTabControlWithCustomStyle.GrabTab(dockedWindowVM);
41+
return true;
42+
}
43+
}
44+
return false;
45+
}
1446
}
1547
}

Demo/Demo.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@
107107
<Compile Include="ViewModel\ViewModelMainWindow.cs" />
108108
<Compile Include="ViewModel\ViewModelLocator.cs" />
109109
<Compile Include="ViewModel\ViewModelPinnedTabExampleWindow.cs" />
110+
<Compile Include="WindowBase.cs" />
110111
<Page Include="CustomStyleExampleWindow.xaml">
111112
<SubType>Designer</SubType>
112113
<Generator>MSBuild:Compile</Generator>

Demo/MainWindow.xaml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
<Window x:Name="window"
1+
<local:WindowBase
22
x:Class="Demo.MainWindow"
33
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
44
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
55
Title="ChromeTabs Demo"
66
Height="600"
77
Width="700"
8+
xmlns:local="clr-namespace:Demo"
89
xmlns:vm="clr-namespace:Demo.ViewModel"
910
xmlns:usercontrols="clr-namespace:Demo.UserControls"
1011
xmlns:ct="clr-namespace:ChromeTabs;assembly=ChromeTabs"
@@ -46,7 +47,7 @@
4647
CloseTabCommand="{Binding CloseTabCommand}"
4748
ReorderTabsCommand="{Binding ReorderTabsCommand}"
4849
TabTearTriggerDistance="10"
49-
TabDraggedOutsideBonds="ChromeTabControl_TabDraggedOutsideBonds">
50+
TabDraggedOutsideBonds="TabControl_TabDraggedOutsideBonds">
5051
<!--We override the control template here to show how you can modify the properties of tab panel and content presenter-->
5152
<ct:ChromeTabControl.Template>
5253
<ControlTemplate TargetType="{x:Type ct:ChromeTabControl}">
@@ -162,4 +163,4 @@
162163
</StackPanel>
163164

164165
</Grid>
165-
</Window>
166+
</local:WindowBase>

Demo/MainWindow.xaml.cs

Lines changed: 17 additions & 154 deletions
Original file line numberDiff line numberDiff line change
@@ -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();

Demo/PinnedTabExampleWindow.xaml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<Window x:Class="Demo.PinnedTabExampleWindow"
1+
<local:WindowBase x:Class="Demo.PinnedTabExampleWindow"
22
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
33
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
44
xmlns:local="clr-namespace:Demo"
@@ -36,6 +36,7 @@
3636
MinimumTabWidth="40"
3737
PinnedTabWidth="50"
3838
MaximumTabWidth="125"
39+
TabDraggedOutsideBonds="TabControl_TabDraggedOutsideBonds"
3940
ContainerItemPreparedForOverride="TabControl_ContainerItemPreparedForOverride">
4041
<!--We override the control template here to show how you can modify the properties of tab panel and content presenter-->
4142
<ct:ChromeTabControl.Template>
@@ -108,4 +109,4 @@
108109
</ct:ChromeTabControl.ItemTemplate>
109110
</ct:ChromeTabControl>
110111
</Grid>
111-
</Window>
112+
</local:WindowBase>

Demo/PinnedTabExampleWindow.xaml.cs

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ namespace Demo
77
/// <summary>
88
/// Interaction logic for PinnedTabExample.xaml
99
/// </summary>
10-
public partial class PinnedTabExampleWindow
10+
public partial class PinnedTabExampleWindow : WindowBase
1111
{
1212
public PinnedTabExampleWindow()
1313
{
@@ -22,5 +22,35 @@ private void TabControl_ContainerItemPreparedForOverride(object sender, Containe
2222
e.TabItem.IsPinned = viewModel.IsPinned;
2323
}
2424
}
25+
26+
private void TabControl_TabDraggedOutsideBonds(object sender, TabDragEventArgs e)
27+
{
28+
TabBase draggedTab = e.Tab as TabBase;
29+
if (TryDragTabToWindow(e.CursorPosition, draggedTab))
30+
{
31+
//Set Handled to true to tell the tab control that we have dragged the tab to a window, and the tab should be closed.
32+
e.Handled = true;
33+
}
34+
}
35+
36+
protected override bool TryDockWindow(Point position, TabBase dockedWindowVM)
37+
{
38+
//Hit test against the tab control
39+
if (MyChromeTabControlWithPinnedTabs.InputHitTest(position) is FrameworkElement element)
40+
{
41+
////test if the mouse is over the tab panel or a tab item.
42+
if (CanInsertTabItem(element))
43+
{
44+
//TabBase dockedWindowVM = (TabBase)win.DataContext;
45+
ViewModelExampleBase vm = (ViewModelExampleBase)DataContext;
46+
vm.ItemCollection.Add(dockedWindowVM);
47+
vm.SelectedTab = dockedWindowVM;
48+
//We run this method on the tab control for it to grab the tab and position it at the mouse, ready to move again.
49+
MyChromeTabControlWithPinnedTabs.GrabTab(dockedWindowVM);
50+
return true;
51+
}
52+
}
53+
return false;
54+
}
2555
}
2656
}

0 commit comments

Comments
 (0)