6
6
using System . Runtime . CompilerServices ;
7
7
using TabViewTear . Models ;
8
8
using TabViewTear . Services ;
9
+ using Windows . ApplicationModel . DataTransfer ;
9
10
using Windows . UI . Core ;
10
11
using Windows . UI . ViewManagement ;
11
12
using Windows . UI . Xaml ;
@@ -16,6 +17,11 @@ namespace TabViewTear.Views
16
17
{
17
18
public sealed partial class MainPage : Page , INotifyPropertyChanged
18
19
{
20
+ private const string DataIdentifier = "TabData" ;
21
+ private const string DataIndex = "TabIndex" ;
22
+ private const string DataWindow = "TabWindow" ;
23
+ private const string CommandClose = "Close" ;
24
+
19
25
ObservableCollection < DataItem > TabItems = new ObservableCollection < DataItem > ( ) ;
20
26
21
27
public MainPage ( )
@@ -26,6 +32,8 @@ public MainPage()
26
32
public event PropertyChangedEventHandler PropertyChanged ;
27
33
28
34
private ViewLifetimeControl _viewLifetimeControl ;
35
+
36
+ #region Handle Window Lifetime
29
37
protected override void OnNavigatedTo ( NavigationEventArgs e )
30
38
{
31
39
base . OnNavigatedTo ( e ) ;
@@ -36,6 +44,7 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
36
44
_viewLifetimeControl . StartViewInUse ( ) ;
37
45
// Register for window close
38
46
_viewLifetimeControl . Released += OnViewLifetimeControlReleased ;
47
+ _viewLifetimeControl . MessageReceived += OnViewLifetimeControlMessageReceived ;
39
48
// Deserialize passed in item to display in this window
40
49
TabItems . Add ( JsonConvert . DeserializeObject < DataItem > ( _viewLifetimeControl . Context . ToString ( ) ) ) ;
41
50
_viewLifetimeControl . Context = null ;
@@ -45,9 +54,18 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
45
54
{
46
55
// Main Window Start
47
56
InitializeTestData ( ) ;
57
+
58
+ WindowManagerService . Current . MainWindowMessageReceived += OnViewLifetimeControlMessageReceived ;
48
59
}
49
60
}
50
61
62
+ private MessageEventArgs _lastMsg ;
63
+
64
+ private async void OnViewLifetimeControlMessageReceived ( object sender , MessageEventArgs e )
65
+ {
66
+ _lastMsg = e ; // Store to complete in DragItemsCompleted.
67
+ }
68
+
51
69
private async void OnViewLifetimeControlReleased ( object sender , EventArgs e )
52
70
{
53
71
_viewLifetimeControl . Released -= OnViewLifetimeControlReleased ;
@@ -56,7 +74,9 @@ await WindowManagerService.Current.MainDispatcher.RunAsync(CoreDispatcherPriorit
56
74
WindowManagerService . Current . SecondaryViews . Remove ( _viewLifetimeControl ) ;
57
75
} ) ;
58
76
}
77
+ #endregion
59
78
79
+ #region Handle Dragging Tab to Create Window
60
80
private async void Items_TabDraggedOutside ( object sender , Microsoft . Toolkit . Uwp . UI . Controls . TabDraggedOutsideEventArgs e )
61
81
{
62
82
if ( e . Item is DataItem data )
@@ -69,12 +89,15 @@ private async void Items_TabDraggedOutside(object sender, Microsoft.Toolkit.Uwp.
69
89
70
90
if ( TabItems . Count == 0 )
71
91
{
92
+ // TODO: If drag wasn't received by another window and last tab, ignore?
72
93
// No tabs left on main window, 'switch' to window just created to hide the main view
73
94
await ApplicationViewSwitcher . SwitchAsync ( lifetimecontrol . Id , ApplicationView . GetForCurrentView ( ) . Id , ApplicationViewSwitchingOptions . ConsolidateViews ) ;
74
95
}
75
96
}
76
97
}
98
+ #endregion
77
99
100
+ #region Handle Tab Change Updating Window Title
78
101
private void Items_SelectionChanged ( object sender , SelectionChangedEventArgs e )
79
102
{
80
103
// Update window title with current item
@@ -84,6 +107,100 @@ private void Items_SelectionChanged(object sender, SelectionChangedEventArgs e)
84
107
ApplicationView . GetForCurrentView ( ) . Title = data . Title ;
85
108
}
86
109
}
110
+ #endregion
111
+
112
+ #region Handle Dragging Tabs between windows
113
+ private void Items_DragItemsStarting ( object sender , DragItemsStartingEventArgs e )
114
+ {
115
+ // In Initial Window we need to serialize our tab data.
116
+ var item = e . Items . FirstOrDefault ( ) ;
117
+
118
+ if ( item is DataItem data )
119
+ {
120
+ // Add actual data
121
+ e . Data . Properties . Add ( DataIdentifier , JsonConvert . SerializeObject ( data ) ) ;
122
+ // Add our index so we know where to remove from later (if needed)
123
+ e . Data . Properties . Add ( DataIndex , Items . IndexFromContainer ( Items . ContainerFromItem ( data ) ) ) ;
124
+ // Add Window Id to know if we're transferring to a different window.
125
+ e . Data . Properties . Add ( DataWindow , ApplicationView . GetForCurrentView ( ) . Id ) ;
126
+ }
127
+ }
128
+
129
+ private void Items_DragOver ( object sender , DragEventArgs e )
130
+ {
131
+ // Called before we drop to see if we will accept a drop.
132
+
133
+ // Do we have Tab Data?
134
+ if ( e . DataView . Properties . ContainsKey ( DataIdentifier ) )
135
+ {
136
+ // Tell OS that we allow moving item.
137
+ e . AcceptedOperation = DataPackageOperation . Move ;
138
+ }
139
+ }
140
+
141
+ private void Items_Drop ( object sender , DragEventArgs e )
142
+ {
143
+ // Called when we actually get the drop, let's get the data and add our tab.
144
+ var pos = e . GetPosition ( this ) ;
145
+
146
+ if ( e . DataView . Properties . TryGetValue ( DataIdentifier , out object value ) && value is string str )
147
+ {
148
+ var data = JsonConvert . DeserializeObject < DataItem > ( str ) ;
149
+
150
+ if ( data != null )
151
+ {
152
+ //var minpos = pos;
153
+ //var mindist = 1000.0;
154
+ //var minindex = -1;
155
+ //foreach (var item in Items.Items)
156
+ //{
157
+ // var tab = Items.ContainerFromItem(item);
158
+ // var p = e.GetPosition(tab as UIElement);
159
+ // var amt = Math.Abs(p.X - minpos.X) + Math.Abs(p.Y - minpos.Y);
160
+ // if (amt < mindist)
161
+ // {
162
+ // minindex = Items.IndexFromContainer(tab);
163
+ // mindist = amt;
164
+ // minpos = p;
165
+ // }
166
+ //}
167
+
168
+
169
+ // TODO: Figure out how to insert this in the right place.
170
+ TabItems . Add ( data ) ;
171
+
172
+ Items . SelectedItem = data ; // Select new item.
173
+
174
+ // Send message to origintator to remove the tab.
175
+ WindowManagerService . Current . SendMessage ( ( e . DataView . Properties [ DataWindow ] as int ? ) . Value , CommandClose , e . DataView . Properties [ DataIndex ] ) ;
176
+ }
177
+ }
178
+ }
179
+
180
+ private async void Items_DragItemsCompleted ( ListViewBase sender , DragItemsCompletedEventArgs args )
181
+ {
182
+ if ( args . DropResult == DataPackageOperation . Move && _lastMsg != null )
183
+ {
184
+ switch ( _lastMsg . Message )
185
+ {
186
+ case CommandClose :
187
+ if ( _lastMsg . Data is int value )
188
+ {
189
+ TabItems . RemoveAt ( value ) ;
190
+
191
+ if ( TabItems . Count == 0 )
192
+ {
193
+ // No tabs left on main window, 'switch' to window just created to hide the main view
194
+ await ApplicationViewSwitcher . SwitchAsync ( _lastMsg . FromId , ApplicationView . GetForCurrentView ( ) . Id , ApplicationViewSwitchingOptions . ConsolidateViews ) ;
195
+ }
196
+ }
197
+
198
+ _lastMsg = null ;
199
+ break ;
200
+ }
201
+ }
202
+ }
203
+ #endregion
87
204
88
205
private void Set < T > ( ref T storage , T value , [ CallerMemberName ] string propertyName = null )
89
206
{
0 commit comments