我从 Xaml 控件库中复制了代码。当我运行并拖动列表项时,应用程序将关闭。如果我在调试中运行,F10 不会引导我进入正在破坏的代码部分。事实上,该应用程序保持打开状态,但没有任何反应。我难住了。
(这是来自winui3-preview 4)
Contact.txt
https://github.com/microsoft/Xaml-Controls-Gallery/blob/master/XamlControlsGallery/Assets/Contacts.txt
// ListBoxPage.xaml (I know bad naming)
<Page
x:Class="NavTest.ListBoxPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:NavTest"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local1="using:Windows.ApplicationModel.Contacts"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<!--
ListViews with grouped items must be bound to a CollectionViewSource, as shown below.
This CollectionViewSource is defined in the XAML below, but is bound to an ItemsSource in the C#
code-behind. See the C# code below for more details on how to create/bind to a grouped list.
-->
<CollectionViewSource x:Name="ContactsCVS" IsSourceGrouped="True"/>
<!--
In this example, the ListView's ItemTemplate property is bound to a data template (shown below)
called ContactListViewTemplate, defined in a Page.Resources section.
-->
<DataTemplate x:Key="ContactListViewTemplate" x:DataType="local:Contact">
<TextBlock Text="{x:Bind Name}" x:Phase="1" Margin="0,5,0,5"/>
</DataTemplate>
</Page.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView
Grid.Row="0"
Grid.Column="0"
x:Name="BaseExample"
SelectionMode="Extended"
ItemsSource="{x:Bind ContactsCVS.View, Mode=OneWay}"
ItemTemplate="{StaticResource ContactListViewTemplate}"
BorderThickness="1"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
Width="550"
Height="400"
CanDragItems="True"
CanReorderItems="True"
AllowDrop="True"
DragItemsStarting="BaseExample_DragItemsStarting"
DragOver="BaseExample_DragOver"
Drop="BaseExample_Drop"
HorizontalAlignment="Left">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel AreStickyGroupHeadersEnabled="True"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="local:GroupInfoList">
<Border>
<TextBlock Text="{x:Bind Key}" Style="{ThemeResource TitleTextBlockStyle}" />
</Border>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
<ListView
Grid.Row="0"
Grid.Column="1"
x:Name="BaseExample2"
SelectionMode="Extended"
ItemTemplate="{StaticResource ContactListViewTemplate}"
BorderThickness="1"
BorderBrush="{ThemeResource SystemControlForegroundBaseMediumLowBrush}"
Width="550"
Height="400"
CanDragItems="True"
CanReorderItems="True"
AllowDrop="True"
DragItemsStarting="BaseExample2_DragItemsStarting"
DragOver="BaseExample2_DragOver"
DragEnter="BaseExample2_DragEnter"
Drop="BaseExample_Drop"
HorizontalAlignment="Left">
</ListView>
</Grid>
// ListBoxPage.xaml.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.Storage;
using Windows.UI.WebUI;
// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.
namespace NavTest
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class ListBoxPage : Page
{
ObservableCollection<Contact> contacts1 = new ObservableCollection<Contact>();
ObservableCollection<Contact> contacts2 = new ObservableCollection<Contact>();
public ListBoxPage()
{
this.InitializeComponent();
}
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
// The ItemsSource for the ListView is generated by a method of the Contact class called
// GetContactsAsync().This method pulls data from an internal data source and creates
// Contact objects from that data. Those Contact objects are placed in a collection
// which is returned from the GetContactsAsync() function.
contacts1 = await Contact.GetContactsAsync();
contacts2 = new ObservableCollection<Contact>();
BaseExample.ItemsSource = contacts1;
BaseExample2.ItemsSource = contacts2;
ContactsCVS.Source = await Contact.GetContactsGroupedAsync();
}
private void BaseExample_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
// Prepare a string with one dragged item per line
StringBuilder items = new StringBuilder();
foreach (Contact item in e.Items)
{
if (items.Length > 0) { items.AppendLine(); }
if (item.ToString() != null)
{
// Append name from contact object onto data string
items.Append(item.ToString() + " " + item.Company);
}
}
// Set the content of the DataPackage
e.Data.SetText(items.ToString());
e.Data.RequestedOperation = DataPackageOperation.Move;
}
private void BaseExample_DragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Move;
}
private async void BaseExample_Drop(object sender, DragEventArgs e)
{
ListView target = (ListView)sender;
if (e.DataView.Contains(StandardDataFormats.Text))
{
DragOperationDeferral def = e.GetDeferral();
string s = await e.DataView.GetTextAsync();
string[] items = s.Split('\n');
foreach (string item in items)
{
// Create Contact object from string, add to existing target ListView
string[] info = item.Split(" ", 3);
Contact temp = new Contact(info[0], info[1], info[2]);
// Find the insertion index:
Windows.Foundation.Point pos = e.GetPosition(target.ItemsPanelRoot);
// Find which ListView is the target, find height of first item
ListViewItem sampleItem;
if (target.Name == "BaseExample")
{
sampleItem = (ListViewItem)BaseExample2.ContainerFromIndex(0);
}
// Only other case is target = DragDropListView2
else
{
sampleItem = (ListViewItem)BaseExample.ContainerFromIndex(0);
}
// Adjust ItemHeight for margins
double itemHeight = sampleItem.ActualHeight + sampleItem.Margin.Top + sampleItem.Margin.Bottom;
// Find index based on dividing number of items by height of each item
int index = Math.Min(target.Items.Count - 1, (int)(pos.Y / itemHeight));
// Find the item that we want to drop
ListViewItem targetItem = (ListViewItem)target.ContainerFromIndex(index); ;
// Figure out if to insert above or below
Windows.Foundation.Point positionInItem = e.GetPosition(targetItem);
if (positionInItem.Y > itemHeight / 2)
{
index++;
}
// Don't go out of bounds
index = Math.Min(target.Items.Count, index);
// Find correct source list
if (target.Name == "BaseExample")
{
// Find the ItemsSource for the target ListView and insert
contacts1.Insert(index, temp);
//Go through source list and remove the items that are being moved
foreach (Contact contact in BaseExample2.Items)
{
if (contact.FirstName == temp.FirstName && contact.LastName == temp.LastName && contact.Company == temp.Company)
{
contacts2.Remove(contact);
break;
}
}
}
else if (target.Name == "BaseExample2")
{
contacts2.Insert(index, temp);
foreach (Contact contact in BaseExample.Items)
{
if (contact.FirstName == temp.FirstName && contact.LastName == temp.LastName && contact.Company == temp.Company)
{
contacts1.Remove(contact);
break;
}
}
}
}
e.AcceptedOperation = DataPackageOperation.Move;
def.Complete();
}
}
private void BaseExample_DragEnter(object sender, DragEventArgs e)
{
// We don't want to show the Move icon
e.DragUIOverride.IsGlyphVisible = false;
}
private void BaseExample2_DragItemsStarting(object sender, DragItemsStartingEventArgs e)
{
if (e.Items.Count == 1)
{
// Prepare ListViewItem to be moved
Contact tmp = (Contact)e.Items[0];
e.Data.SetText(tmp.FirstName + " " + tmp.LastName + " " + tmp.Company);
e.Data.RequestedOperation = DataPackageOperation.Move;
}
}
private void BaseExample2_DragOver(object sender, DragEventArgs e)
{
e.AcceptedOperation = DataPackageOperation.Move;
}
private async void BaseExample2_Drop(object sender, DragEventArgs e)
{
ListView target = (ListView)sender;
if (e.DataView.Contains(StandardDataFormats.Text))
{
DragOperationDeferral def = e.GetDeferral();
string s = await e.DataView.GetTextAsync();
string[] items = s.Split('\n');
foreach (string item in items)
{
// Create Contact object from string, add to existing target ListView
string[] info = item.Split(" ", 3);
Contact temp = new Contact(info[0], info[1], info[2]);
// Find the insertion index:
Windows.Foundation.Point pos = e.GetPosition(target.ItemsPanelRoot);
// Find which ListView is the target, find height of first item
ListViewItem sampleItem;
if (target.Name == "BaseExample")
{
sampleItem = (ListViewItem)BaseExample2.ContainerFromIndex(0);
}
// Only other case is target = DragDropListView2
else
{
sampleItem = (ListViewItem)BaseExample.ContainerFromIndex(0);
}
// Adjust ItemHeight for margins
double itemHeight = sampleItem.ActualHeight + sampleItem.Margin.Top + sampleItem.Margin.Bottom;
// Find index based on dividing number of items by height of each item
int index = Math.Min(target.Items.Count - 1, (int)(pos.Y / itemHeight));
// Find the item that we want to drop
ListViewItem targetItem = (ListViewItem)target.ContainerFromIndex(index); ;
// Figure out if to insert above or below
Windows.Foundation.Point positionInItem = e.GetPosition(targetItem);
if (positionInItem.Y > itemHeight / 2)
{
index++;
}
// Don't go out of bounds
index = Math.Min(target.Items.Count, index);
// Find correct source list
if (target.Name == "BaseExample")
{
// Find the ItemsSource for the target ListView and insert
contacts1.Insert(index, temp);
//Go through source list and remove the items that are being moved
foreach (Contact contact in BaseExample2.Items)
{
if (contact.FirstName == temp.FirstName && contact.LastName == temp.LastName && contact.Company == temp.Company)
{
contacts2.Remove(contact);
break;
}
}
}
else if (target.Name == "BaseExample2")
{
contacts2.Insert(index, temp);
foreach (Contact contact in BaseExample.Items)
{
if (contact.FirstName == temp.FirstName && contact.LastName == temp.LastName && contact.Company == temp.Company)
{
contacts1.Remove(contact);
break;
}
}
}
}
e.AcceptedOperation = DataPackageOperation.Move;
def.Complete();
}
}
private void BaseExample2_DragEnter(object sender, DragEventArgs e)
{
// We don't want to show the Move icon
e.DragUIOverride.IsGlyphVisible = false;
}
}
// C# code-behind
// The data template is defined to display a Contact object (class definition shown below), and the text
// displayed is bound to the Contact object's Name attribute.
public class Contact
{
public string FirstName { get; private set; }
public string LastName { get; private set; }
public string Company { get; private set; }
public string Name => FirstName + " " + LastName;
public static string ContactsPath => $@"{AppDomain.CurrentDomain.BaseDirectory}\Assets\Contacts.txt";
public Contact(string firstName, string lastName, string company)
{
FirstName = firstName;
LastName = lastName;
Company = company;
}
public override string ToString()
{
return Name;
}
#region Public Methods
public static async Task<ObservableCollection<Contact>> GetContactsAsync()
{
string contactsPath = $@"{AppDomain.CurrentDomain.BaseDirectory}\Assets\Contacts.txt";
Uri contactsUri = new Uri(contactsPath, UriKind.RelativeOrAbsolute);
Uri _contactsUri = new Uri(ContactsPath, UriKind.RelativeOrAbsolute);
StorageFile file = await StorageFile.GetFileFromPathAsync(contactsPath);
IList<string> lines = await FileIO.ReadLinesAsync(file);
ObservableCollection<Contact> contacts = new ObservableCollection<Contact>();
for (int i = 0; i < lines.Count; i += 3)
{
contacts.Add(new Contact(lines[i], lines[i + 1], lines[i + 2]));
}
return contacts;
}
// To create a collection of grouped items, create a query that groups
// an existing list, or returns a grouped collection from a database.
// The following method is used to create the ItemsSource for our CollectionViewSource:
public static async Task<ObservableCollection<GroupInfoList>> GetContactsGroupedAsync()
{
// Grab Contact objects from pre-existing list (list is returned from function GetContactsAsync())
var query = from item in await GetContactsAsync()
// Group the items returned from the query, sort and select the ones you want to keep
group item by item.LastName.Substring(0, 1).ToUpper() into g
orderby g.Key
// GroupInfoList is a simple custom class that has an IEnumerable type attribute, and
// a key attribute. The IGrouping-typed variable g now holds the Contact objects,
// and these objects will be used to create a new GroupInfoList object.
select new GroupInfoList(g) { Key = g.Key };
return new ObservableCollection<GroupInfoList>(query);
}
#endregion
}
// GroupInfoList class definition:
public class GroupInfoList : List<object>
{
public GroupInfoList(IEnumerable<object> items) : base(items)
{
}
public object Key { get; set; }
}
}