66using System . Runtime . CompilerServices ;
77using TabViewTear . Models ;
88using TabViewTear . Services ;
9+ using Windows . ApplicationModel . DataTransfer ;
910using Windows . UI . Core ;
1011using Windows . UI . ViewManagement ;
1112using Windows . UI . Xaml ;
@@ -16,6 +17,11 @@ namespace TabViewTear.Views
1617{
1718 public sealed partial class MainPage : Page , INotifyPropertyChanged
1819 {
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+
1925 ObservableCollection < DataItem > TabItems = new ObservableCollection < DataItem > ( ) ;
2026
2127 public MainPage ( )
@@ -26,6 +32,8 @@ public MainPage()
2632 public event PropertyChangedEventHandler PropertyChanged ;
2733
2834 private ViewLifetimeControl _viewLifetimeControl ;
35+
36+ #region Handle Window Lifetime
2937 protected override void OnNavigatedTo ( NavigationEventArgs e )
3038 {
3139 base . OnNavigatedTo ( e ) ;
@@ -36,6 +44,7 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
3644 _viewLifetimeControl . StartViewInUse ( ) ;
3745 // Register for window close
3846 _viewLifetimeControl . Released += OnViewLifetimeControlReleased ;
47+ _viewLifetimeControl . MessageReceived += OnViewLifetimeControlMessageReceived ;
3948 // Deserialize passed in item to display in this window
4049 TabItems . Add ( JsonConvert . DeserializeObject < DataItem > ( _viewLifetimeControl . Context . ToString ( ) ) ) ;
4150 _viewLifetimeControl . Context = null ;
@@ -45,9 +54,18 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
4554 {
4655 // Main Window Start
4756 InitializeTestData ( ) ;
57+
58+ WindowManagerService . Current . MainWindowMessageReceived += OnViewLifetimeControlMessageReceived ;
4859 }
4960 }
5061
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+
5169 private async void OnViewLifetimeControlReleased ( object sender , EventArgs e )
5270 {
5371 _viewLifetimeControl . Released -= OnViewLifetimeControlReleased ;
@@ -56,7 +74,9 @@ await WindowManagerService.Current.MainDispatcher.RunAsync(CoreDispatcherPriorit
5674 WindowManagerService . Current . SecondaryViews . Remove ( _viewLifetimeControl ) ;
5775 } ) ;
5876 }
77+ #endregion
5978
79+ #region Handle Dragging Tab to Create Window
6080 private async void Items_TabDraggedOutside ( object sender , Microsoft . Toolkit . Uwp . UI . Controls . TabDraggedOutsideEventArgs e )
6181 {
6282 if ( e . Item is DataItem data )
@@ -69,12 +89,15 @@ private async void Items_TabDraggedOutside(object sender, Microsoft.Toolkit.Uwp.
6989
7090 if ( TabItems . Count == 0 )
7191 {
92+ // TODO: If drag wasn't received by another window and last tab, ignore?
7293 // No tabs left on main window, 'switch' to window just created to hide the main view
7394 await ApplicationViewSwitcher . SwitchAsync ( lifetimecontrol . Id , ApplicationView . GetForCurrentView ( ) . Id , ApplicationViewSwitchingOptions . ConsolidateViews ) ;
7495 }
7596 }
7697 }
98+ #endregion
7799
100+ #region Handle Tab Change Updating Window Title
78101 private void Items_SelectionChanged ( object sender , SelectionChangedEventArgs e )
79102 {
80103 // Update window title with current item
@@ -84,6 +107,100 @@ private void Items_SelectionChanged(object sender, SelectionChangedEventArgs e)
84107 ApplicationView . GetForCurrentView ( ) . Title = data . Title ;
85108 }
86109 }
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
87204
88205 private void Set < T > ( ref T storage , T value , [ CallerMemberName ] string propertyName = null )
89206 {
0 commit comments