diff --git a/Samples/XamlDragAndDrop/cpp/DragAndDropSampleNative.vcxproj b/Samples/XamlDragAndDrop/cpp/DragAndDropSampleNative.vcxproj index 104df5e012..cb28e36aee 100644 --- a/Samples/XamlDragAndDrop/cpp/DragAndDropSampleNative.vcxproj +++ b/Samples/XamlDragAndDrop/cpp/DragAndDropSampleNative.vcxproj @@ -101,10 +101,10 @@ - - $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);..\..\..\SharedContent\cpp - - + + $(VC_IncludePath);$(UniversalCRT_IncludePath);$(WindowsSDK_IncludePath);..\..\..\SharedContent\cpp + + /bigobj %(AdditionalOptions) 4453;28204 @@ -158,6 +158,9 @@ Scenario3_StartDragAsync.xaml + + Scenario4_MoveBetweenListView.xaml + @@ -172,6 +175,7 @@ Styles\Styles.xaml + @@ -203,6 +207,9 @@ Scenario3_StartDragAsync.xaml + + Scenario4_MoveBetweenListView.xaml + diff --git a/Samples/XamlDragAndDrop/cpp/DragAndDropSampleNative.vcxproj.filters b/Samples/XamlDragAndDrop/cpp/DragAndDropSampleNative.vcxproj.filters index 9c3efd46c9..c99fbe24a7 100644 --- a/Samples/XamlDragAndDrop/cpp/DragAndDropSampleNative.vcxproj.filters +++ b/Samples/XamlDragAndDrop/cpp/DragAndDropSampleNative.vcxproj.filters @@ -39,6 +39,7 @@ + diff --git a/Samples/XamlDragAndDrop/cpp/SampleConfiguration.cpp b/Samples/XamlDragAndDrop/cpp/SampleConfiguration.cpp index 59ac22360a..8dd04c12df 100644 --- a/Samples/XamlDragAndDrop/cpp/SampleConfiguration.cpp +++ b/Samples/XamlDragAndDrop/cpp/SampleConfiguration.cpp @@ -19,5 +19,6 @@ Platform::Array^ MainPage::scenariosInner = ref new Platform::Array + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/XamlDragAndDrop/cpp/Scenario4_MoveBetweenListView.xaml.cpp b/Samples/XamlDragAndDrop/cpp/Scenario4_MoveBetweenListView.xaml.cpp new file mode 100644 index 0000000000..d5aead4065 --- /dev/null +++ b/Samples/XamlDragAndDrop/cpp/Scenario4_MoveBetweenListView.xaml.cpp @@ -0,0 +1,148 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* +#include "pch.h" +#include "Scenario4_MoveBetweenListView.xaml.h" + +using namespace concurrency; +using namespace SDKTemplate; +using namespace Platform; +using namespace Platform::Collections; +using namespace Windows::Foundation; +using namespace Windows::Foundation::Collections; +using namespace Windows::UI::Xaml; +using namespace Windows::UI::Xaml::Controls; +using namespace Windows::UI::Xaml::Controls::Primitives; +using namespace Windows::UI::Xaml::Data; +using namespace Windows::UI::Xaml::Input; +using namespace Windows::UI::Xaml::Media; +using namespace Windows::UI::Xaml::Navigation; +using namespace Windows::ApplicationModel::DataTransfer; + +Scenario4_MoveBetweenListView::Scenario4_MoveBetweenListView() : rootPage(MainPage::Current) +{ + InitializeComponent(); + + _source = GetSampleData(); + _target = ref new Vector(); + SourceListView->ItemsSource = _source; + TargetListView->ItemsSource = _target; +} + +Vector^ Scenario4_MoveBetweenListView::GetSampleData() +{ + return ref new Vector( + { + ref new String(L"My Research Paper"), + ref new String(L"Electricity Bill"), + ref new String(L"My To-do list"), + ref new String(L"TV sales receipt"), + ref new String(L"Water Bill"), + ref new String(L"Grocery List"), + ref new String(L"Superbowl schedule"), + ref new String(L"World Cup E-ticket") + }); +} + +/// +/// DragItemsStarting is called when the Drag and Drop operation starts +/// We take advantage of it to set the content of the DataPackage +/// as well as indicate which operations are supported +/// +/// +/// +void Scenario4_MoveBetweenListView::ListView_DragItemsStarting(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e) +{ + // Prepare a string with one dragged item per line + // Set the content of the DataPackage + if (e->Items->Size > 0) + { + e->Data->SetText(dynamic_cast(e->Items->GetAt(0))); + // As we want our Reference list to say intact, we only allow Move + e->Data->RequestedOperation = DataPackageOperation::Move; + } +} + +/// +/// DragOver is called when the dragged pointer moves over a UIElement with AllowDrop=True +/// We need to return an AcceptedOperation != None in either DragOver or DragEnter +/// +/// +/// +void Scenario4_MoveBetweenListView::ListView_DragOver(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e) +{ + // Our list only accepts text + e->AcceptedOperation = (e->DataView->Contains(StandardDataFormats::Text)) ? DataPackageOperation::Move : DataPackageOperation::None; +} + +/// +/// We need to return the effective operation from Drop +/// This is not important for our source ListView, but it might be if the user +/// drags text from another source +/// +/// +/// +void Scenario4_MoveBetweenListView::ListView_Drop(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e) +{ + // This test is in theory not needed as we returned DataPackageOperation.None if + // the DataPackage did not contained text. However, it is always better if each + // method is robust by itself + if (e->DataView->Contains(StandardDataFormats::Text)) + { + // We need to take a Deferral as we won't be able to confirm the end + // of the operation synchronously + auto def = e->GetDeferral(); + create_task(e->DataView->GetTextAsync()).then([def, this, sender, e](String^ s) + { + // Get the lists we need to work with. + auto sourceList = (sender->Equals(TargetListView) ? _source : _target); + auto targetList = (sender->Equals(TargetListView) ? _target : _source); + + // Remove item from other list + unsigned j; + if (sourceList->IndexOf(s, &j)) + { + sourceList->RemoveAt(j); + } + + // First we need to get the position in the List to drop to + auto listview = dynamic_cast(sender); + int index = -1; + + // Determine which items in the list our pointer is inbetween. + for (int i = 0; i < listview->Items->Size; i++) + { + auto item = dynamic_cast(listview->ContainerFromIndex(i)); + + auto p = e->GetPosition(item); + + if (p.Y - item->ActualHeight < 0) + { + index = i; + break; + } + } + + if (index < 0) + { + // We didn't find a transition point, so we're at the end of the list + targetList->Append(s); + } + else if (index < listview->Items->Size) + { + // Otherwise, insert at the provided index. + targetList->InsertAt(index, s); + } + + e->AcceptedOperation = DataPackageOperation::Copy; + def->Complete(); + }); + } +} diff --git a/Samples/XamlDragAndDrop/cpp/Scenario4_MoveBetweenListView.xaml.h b/Samples/XamlDragAndDrop/cpp/Scenario4_MoveBetweenListView.xaml.h new file mode 100644 index 0000000000..265c285edd --- /dev/null +++ b/Samples/XamlDragAndDrop/cpp/Scenario4_MoveBetweenListView.xaml.h @@ -0,0 +1,38 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +#pragma once + +#include "Scenario4_MoveBetweenListView.g.h" +#include "MainPage.xaml.h" + +namespace SDKTemplate +{ + /// + /// An empty page that can be used on its own or navigated to within a Frame. + /// + [Windows::Foundation::Metadata::WebHostHidden] + public ref class Scenario4_MoveBetweenListView sealed + { + public: + Scenario4_MoveBetweenListView(); + private: + MainPage^ rootPage; + + Platform::Collections::Vector^ GetSampleData(); + Platform::Collections::Vector^ _source; + Platform::Collections::Vector^ _target; + + void ListView_DragItemsStarting(Platform::Object^ sender, Windows::UI::Xaml::Controls::DragItemsStartingEventArgs^ e); + void ListView_DragOver(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e); + void ListView_Drop(Platform::Object^ sender, Windows::UI::Xaml::DragEventArgs^ e); + }; +} diff --git a/Samples/XamlDragAndDrop/cs/DragAndDropSampleManaged.csproj b/Samples/XamlDragAndDrop/cs/DragAndDropSampleManaged.csproj index 7429c060c4..fa82f12c1f 100644 --- a/Samples/XamlDragAndDrop/cs/DragAndDropSampleManaged.csproj +++ b/Samples/XamlDragAndDrop/cs/DragAndDropSampleManaged.csproj @@ -99,6 +99,9 @@ Properties\AssemblyInfo.cs + + Scenario4_MoveBetweenListView.xaml + Scenario1_ListView.xaml @@ -125,6 +128,10 @@ MSBuild:Compile Designer + + MSBuild:Compile + Designer + MSBuild:Compile Designer diff --git a/Samples/XamlDragAndDrop/cs/SampleConfiguration.cs b/Samples/XamlDragAndDrop/cs/SampleConfiguration.cs index dcd0fd14fd..d6fc57e4ce 100644 --- a/Samples/XamlDragAndDrop/cs/SampleConfiguration.cs +++ b/Samples/XamlDragAndDrop/cs/SampleConfiguration.cs @@ -24,7 +24,8 @@ public partial class MainPage : Page { new Scenario() { Title="ListView Drag and Drop and Reorder", ClassType=typeof(Scenario1_ListView)}, new Scenario() { Title="Drag UI Customization", ClassType=typeof(Scenario2_DragUICustomization)}, - new Scenario() { Title="StartDragAsync", ClassType=typeof(Scenario3_StartDragAsync)} + new Scenario() { Title="StartDragAsync", ClassType=typeof(Scenario3_StartDragAsync)}, + new Scenario() { Title="Move Between ListViews", ClassType=typeof(Scenario4_MoveBetweenListView)} }; } diff --git a/Samples/XamlDragAndDrop/cs/Scenario4_MoveBetweenListView.xaml b/Samples/XamlDragAndDrop/cs/Scenario4_MoveBetweenListView.xaml new file mode 100644 index 0000000000..77944496fd --- /dev/null +++ b/Samples/XamlDragAndDrop/cs/Scenario4_MoveBetweenListView.xaml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Samples/XamlDragAndDrop/cs/Scenario4_MoveBetweenListView.xaml.cs b/Samples/XamlDragAndDrop/cs/Scenario4_MoveBetweenListView.xaml.cs new file mode 100644 index 0000000000..70abfbc947 --- /dev/null +++ b/Samples/XamlDragAndDrop/cs/Scenario4_MoveBetweenListView.xaml.cs @@ -0,0 +1,151 @@ +//********************************************************* +// +// Copyright (c) Microsoft. All rights reserved. +// This code is licensed under the MIT License (MIT). +// THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF +// ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY +// IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR +// PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT. +// +//********************************************************* + +using Windows.UI.Xaml; +using Windows.UI.Xaml.Controls; +using Windows.UI.Xaml.Navigation; +using SDKTemplate; +using System; +using System.Collections.ObjectModel; +using Windows.ApplicationModel.DataTransfer; +using System.Linq; +using Windows.Foundation; + +namespace DragAndDropSampleManaged +{ + /// + /// This sample shows how to drag a single item between listviews and maintain the user's desired location. + /// + public sealed partial class Scenario4_MoveBetweenListView : Page + { + private MainPage rootPage; + + ObservableCollection _source; + ObservableCollection _target; + + public Scenario4_MoveBetweenListView() + { + this.InitializeComponent(); + + _source = GetSampleData(); + _target = new ObservableCollection(); + SourceListView.ItemsSource = _source; + TargetListView.ItemsSource = _target; + } + private ObservableCollection GetSampleData() + { + return new ObservableCollection + { + "My Research Paper", + "Electricity Bill", + "My To-do list", + "TV sales receipt", + "Water Bill", + "Grocery List", + "Superbowl schedule", + "World Cup E-ticket" + }; + } + + protected override void OnNavigatedTo(NavigationEventArgs e) + { + rootPage = MainPage.Current; + } + + /// + /// DragItemsStarting is called when the Drag and Drop operation starts + /// We take advantage of it to set the content of the DataPackage + /// as well as indicate which operations are supported + /// + /// + /// + private void ListView_DragItemsStarting(object sender, DragItemsStartingEventArgs e) + { + // Prepare a string with one dragged item per line + // Set the content of the DataPackage + e.Data.SetText(e.Items.FirstOrDefault() as string); + // As we want our Reference list to mutate, we only allow Move + e.Data.RequestedOperation = DataPackageOperation.Move; + } + + /// + /// DragOver is called when the dragged pointer moves over a UIElement with AllowDrop=True + /// We need to return an AcceptedOperation != None in either DragOver or DragEnter + /// + /// + /// + private void ListView_DragOver(object sender, DragEventArgs e) + { + // Our list only accepts text + e.AcceptedOperation = (e.DataView.Contains(StandardDataFormats.Text)) ? DataPackageOperation.Move : DataPackageOperation.None; + } + + /// + /// We need to return the effective operation from Drop + /// This is not important for our source ListView, but it might be if the user + /// drags text from another source + /// + /// + /// + private async void ListView_Drop(object sender, DragEventArgs e) + { + // This test is in theory not needed as we returned DataPackageOperation.None if + // the DataPackage did not contained text. However, it is always better if each + // method is robust by itself + if (e.DataView.Contains(StandardDataFormats.Text)) + { + // We need to take a Deferral as we won't be able to confirm the end + // of the operation synchronously + var def = e.GetDeferral(); + var text = await e.DataView.GetTextAsync(); + + // Get the lists we need to work with. + var sourceList = (sender == TargetListView ? _source : _target); + var targetList = (sender == TargetListView ? _target : _source); + + // Remove item from other list + sourceList.Remove(text); + + // First we need to get the position in the List to drop to + var listview = sender as ListView; + var index = -1; + + // Determine which items in the list our pointer is inbetween. + for (int i = 0; i < listview.Items.Count; i++) + { + var item = listview.ContainerFromIndex(i) as ListViewItem; + + var p = e.GetPosition(item); + + if (p.Y - item.ActualHeight < 0) + { + index = i; + break; + } + } + + if (index < 0) + { + // We didn't find a transition point, so we're at the end of the list + targetList.Add(text); + } + else if (index < listview.Items.Count) + { + // Otherwise, insert at the provided index. + targetList.Insert(index, text); + } + + e.AcceptedOperation = DataPackageOperation.Move; + def.Complete(); + } + } + } +}