WinUI3 ListView Selected Items
See the question and my original answer on StackOverflowHere is another answer of course still based on ListViewItem but slightly different, I believe a bit simpler to implement across different WinUI3 supported languages.
The Xaml:
<ListView ItemsSource="{x:Bind MyItems}" SelectionMode="Multiple">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:MyItem">
<ListViewItem IsSelected="{x:Bind IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
<TextBlock Text="{x:Bind Name}" />
</ListViewItem>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
And if you have a data class like this in C#
public class MyItem : INotifyPropertyChanged
{
private bool _isSelected;
public event PropertyChangedEventHandler PropertyChanged;
public string Name { get; set; }
public bool IsSelected
{
get => _isSelected;
set
{
if (_isSelected == value)
return;
_isSelected = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsSelected)));
}
}
}
Or this in C++ (with WinRT), some code ommited for brevity the full project is here https://github.com/smourier/WinUI3Cpp
[bindable]
[default_interface]
runtimeclass FileSystemItem : Microsoft.UI.Xaml.Data.INotifyPropertyChanged
{
String Name { get; };
Boolean IsSelected;
}
struct FileSystemItem : FileSystemItemT<FileSystemItem>
{
hstring Name() { return _name; }
bool IsSelected() const { return _isSelected; }
void IsSelected(bool const& selected){
if (selected == _isSelected)
return;
_isSelected = selected;
RaisePropertyChanged(L"IsSelected");
}
event_token PropertyChanged(PropertyChangedEventHandler const& handler) { return _propertyChanged.add(handler); }
void PropertyChanged(event_token token) { _propertyChanged.remove(token); }
private:
event<PropertyChangedEventHandler> _propertyChanged;
hstring _name;
bool _isSelected;
void RaisePropertyChanged(hstring propertyName)
{
_propertyChanged(*this, PropertyChangedEventArgs(propertyName));
}
};
}
Then the trick is to select initial items in a deferred way, so like this in C#
public sealed partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MyItems.Add(new MyItem { Name = "Bob" });
MyItems.Add(new MyItem { Name = "Alice" });
MyItems.Add(new MyItem { Name = "Carl" });
MyItems.Add(new MyItem { Name = "Donald" });
// select items at initialization
DispatcherQueue.TryEnqueue(DispatcherQueuePriority.Low, () =>
{
MyItems[1].IsSelected = true; // select items 1 & 3
MyItems[3].IsSelected = true;
});
}
public ObservableCollection<MyItem> MyItems { get; } = [];
}
And for example like this in C++
auto source{ single_threaded_observable_vector<TreeViewSample::FileSystemItem>() };
for (auto const& child : someSource())
{
source.Append(child);
}
myListView().ItemsSource(source);
// select items at initialization
DispatcherQueue().TryEnqueue(
Microsoft::UI::Dispatching::DispatcherQueuePriority::Low,
[source]()
{
for (auto const& child : source)
{
child.IsSelected(child.Name().c_str()[0] == 'T'); // select all child with name that starts with 'T'
}
});