У нас есть наблюдаемая коллекция SelectedPartys, если пользователь взаимодействует со списком, который мы добавляем/удаляем в коде позади.
<ListView
x:Name = "LV_Partys"
IsMultiSelectCheckBoxEnabled = "True"
ItemsSource = "{x:Bind ViewModel.PartysOC, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"
SelectionChanged = "LV_Partys_SelectionChanged"
SelectionMode = "Extended">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin = "0">
<Grid.RowDefinitions>
<RowDefinition Height = "Auto" />
<RowDefinition Height = "Auto" />
</Grid.RowDefinitions>
<StackPanel Grid.Row = "0" Orientation = "Horizontal">
<TextBlock Text = "{Binding Name, UpdateSourceTrigger=PropertyChanged}" TextWrapping = "NoWrap" />
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
private ObservableCollection<Party> partysOC;
public ObservableCollection<Party> PartysOC
{
get => partysOC;
set => Set(ref partysOC, value);
}
private void LV_Partys_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var added_items = e.AddedItems.Cast<Party>().ToList();
foreach (var item in added_items)
{
ViewModel.SelectedPartys.Add(item);
}
var removed_items = e.RemovedItems.Cast<Party>().ToList();
foreach (var item in removed_items)
{
ViewModel.SelectedPartys.Remove(item);
}
ViewModel.SelectedPartyChanged();
}
Нам нужно сохранить выбранные элементы ListViews в Db, а затем восстановить их предварительно выбранными в ListView, для этого, я считаю, нам нужно выбрать элемент программно, как мы можем это сделать?





Поскольку вы не можете привязаться к SelectedItems, вам может потребоваться создать элемент управления, производный от ListView:
CustomListView.cs
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Windows.Foundation.Collections;
namespace ListViews;
public class CustomListView : ListView
{
public static readonly DependencyProperty SelectedItemsSourceProperty = DependencyProperty.Register(
nameof(SelectedItemsSource),
typeof(object),
typeof(CustomListView),
new PropertyMetadata(default, (d, e) =>
{
(d as CustomListView)?.UpdateSelectedItemsSource();
}));
public object SelectedItemsSource
{
get => (object)GetValue(SelectedItemsSourceProperty);
set => SetValue(SelectedItemsSourceProperty, value);
}
private CollectionViewSource? SelectedItemsSourceViewSource { get; set; }
private ICollectionView? SelectedItemsSourceView { get; set; }
private void UpdateSelectedItemsSource()
{
if (SelectedItemsSourceView is not null)
{
SelectedItemsSourceView.VectorChanged -= SelectedItemsSourceView_VectorChanged;
}
SelectedItemsSourceViewSource = new()
{
Source = SelectedItemsSource
};
SelectedItemsSourceView = SelectedItemsSourceViewSource.View;
SelectedItemsSourceView.VectorChanged += SelectedItemsSourceView_VectorChanged;
}
private void SelectedItemsSourceView_VectorChanged(IObservableVector<object> sender, IVectorChangedEventArgs @event)
{
switch (@event.CollectionChange)
{
case CollectionChange.Reset:
SelectedItems.Clear();
break;
case CollectionChange.ItemInserted:
if (SelectedItemsSourceView?.Count >= @event.Index)
{
SelectedItems.Add(SelectedItemsSourceView[(int)@event.Index]);
}
break;
case CollectionChange.ItemRemoved:
if (SelectedItemsSourceView?.Count >= @event.Index)
{
SelectedItems.Remove(SelectedItemsSourceView[(int)@event.Index]);
}
break;
case CollectionChange.ItemChanged:
break;
default:
break;
}
}
}
и используйте его так:
MainPage.xaml
<local:CustomListView
ItemsSource = "{x:Bind ViewModel.Items, Mode=OneWay}"
SelectedItemsSource = "{x:Bind ViewModel.SelectedItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectionMode = "Multiple">
<ListView.ItemTemplate>
<DataTemplate x:DataType = "local:Item">
<TextBlock Text = "{x:Bind Id}" />
</DataTemplate>
</ListView.ItemTemplate>
</local:CustomListView>
У ListView есть свойство SelectedItems, такой позор MS сделал его доступным только для чтения, а не DP.
Работает удовольствие, ценю это. Не могу поверить, что это не стандартная функциональность.
В WinUI 3 ListView есть метод, называемый YourListView.SelectRange()
Он недоступен в ListView в xaml, поэтому я вызываю его в коде через вызов обмена сообщениями MVVM.
Файл кода программной части Views
public CodeBehindConstructor()
{
this.InitializeComponent();
// Rx ListView Select items
WeakReferenceMessenger.Default.Register<Msg_ListView_SelectItems>(this, (r, msg) =>
{
SelectParty(msg.Start, msg.Length);
});
}
public void SelectParty(int start, uint length)
{
Debug.WriteLine($"SelectParty start {start} len {length}");
LV_Partys.SelectRange(new ItemIndexRange(start, length));
}
Модель представления
// Select 1st Party
WeakReferenceMessenger.Default.Send(new Msg_ListView_SelectItems { Start = 0, Length = 1});// Start is 0 based, Length isnt it starts at 1
// Select 2nd Party
WeakReferenceMessenger.Default.Send(new Msg_ListView_SelectItems { Start = 1, Length = 1 });
Класс Msg_ListView_SelectItems
public class Msg_ListView_SelectItems
{
public int Start { get; set; }
public uint Length { get; set; }
}
Если ваш режим выбора ListViews — Multiple или Extended, то .SelectRange() выбирает одну последовательную партию элементов, поэтому вы можете вызывать SelectRange более одного раза для элементов, которые не находятся в последовательном порядке.
Спасибо, я посмотрю на это. На данный момент я создал решение, которое я опубликовал, которое выполняет эту работу, но требует использования шины сообщений MVVM.