New WinoListView implementation with multiple selections.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Input;
|
||||
using CommunityToolkit.WinUI;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
@@ -6,6 +7,7 @@ using Wino.Mail.ViewModels.Data;
|
||||
|
||||
namespace Wino.Mail.WinUI.Controls.Advanced;
|
||||
|
||||
[Obsolete("ItemsView sucks. Hard to deal with virtualization issues. Use ListView. This control is here to wise up anyone who tries to use it.")]
|
||||
public partial class WinoItemsView : ItemsView
|
||||
{
|
||||
private const string PART_ScrollView = nameof(PART_ScrollView);
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
using Microsoft.UI.Xaml;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
|
||||
namespace Wino.Mail.WinUI.Controls.ListView;
|
||||
|
||||
public partial class WinoListView : Microsoft.UI.Xaml.Controls.ListView
|
||||
{
|
||||
public bool IsAllSelected => Items.Count == SelectedItems.Count;
|
||||
|
||||
protected override DependencyObject GetContainerForItemOverride() => new WinoListViewItem();
|
||||
|
||||
public bool SelectMailItemContainer(MailItemViewModel mailItemViewModel)
|
||||
{
|
||||
WinoListViewItem? itemContainer = null;
|
||||
|
||||
foreach (var item in Items)
|
||||
{
|
||||
if (item is MailItemViewModel mailItem && mailItem.Id == mailItemViewModel.Id)
|
||||
{
|
||||
itemContainer = ContainerFromItem(mailItemViewModel) as WinoListViewItem;
|
||||
|
||||
break;
|
||||
}
|
||||
else if (item is ThreadMailItemViewModel threadMailItemViewModel && threadMailItemViewModel.HasUniqueId(mailItemViewModel.MailCopy.UniqueId))
|
||||
{
|
||||
itemContainer = ContainerFromItem(threadMailItemViewModel) as WinoListViewItem;
|
||||
|
||||
// Try to get the inner WinoListView.
|
||||
if (itemContainer != null)
|
||||
{
|
||||
itemContainer.IsExpanded = true;
|
||||
|
||||
var innerListViewControl = itemContainer.GetWinoListViewControl();
|
||||
|
||||
if (innerListViewControl != null)
|
||||
{
|
||||
itemContainer = innerListViewControl.ContainerFromItem(mailItemViewModel) as WinoListViewItem;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
itemContainer?.IsSelected = true;
|
||||
|
||||
return itemContainer != null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using CommunityToolkit.Mvvm.Messaging;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Microsoft.UI.Xaml.Media;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
using Wino.Messaging.Client.Mails;
|
||||
|
||||
namespace Wino.Mail.WinUI.Controls.ListView;
|
||||
|
||||
public partial class WinoListViewItem : ListViewItem
|
||||
{
|
||||
public bool IsExpanded
|
||||
{
|
||||
get { return (bool)GetValue(IsExpandedProperty); }
|
||||
set { SetValue(IsExpandedProperty, value); }
|
||||
}
|
||||
|
||||
public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register(nameof(IsExpanded), typeof(bool), typeof(WinoListViewItem), new PropertyMetadata(false, OnIsExpandedChanged));
|
||||
|
||||
public WinoListViewItem()
|
||||
{
|
||||
DefaultStyleKey = typeof(WinoListViewItem);
|
||||
|
||||
RegisterPropertyChangedCallback(IsSelectedProperty, OnIsSelectedChanged);
|
||||
}
|
||||
|
||||
private static void OnIsExpandedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is WinoListViewItem item)
|
||||
{
|
||||
// Handle expansion state change if needed
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnContentChanged(object oldContent, object newContent)
|
||||
{
|
||||
base.OnContentChanged(oldContent, newContent);
|
||||
|
||||
if (oldContent is IMailListItem oldMailItem)
|
||||
{
|
||||
UnregisterSelectionCallback(oldMailItem);
|
||||
}
|
||||
|
||||
if (newContent is IMailListItem newMailItem)
|
||||
{
|
||||
IsSelected = newMailItem.IsSelected;
|
||||
RegisterSelectionCallback(newMailItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnregisterSelectionCallback(IMailListItem mailItem)
|
||||
{
|
||||
mailItem.PropertyChanged -= MailPropChanged;
|
||||
}
|
||||
|
||||
private void RegisterSelectionCallback(IMailListItem mailItem)
|
||||
{
|
||||
mailItem.PropertyChanged += MailPropChanged;
|
||||
}
|
||||
|
||||
// From model
|
||||
private void MailPropChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
|
||||
{
|
||||
if (sender is not IMailListItem mailItem) return;
|
||||
|
||||
if (e.PropertyName == nameof(IMailListItem.IsSelected)) ApplySelectionForContainer(mailItem);
|
||||
}
|
||||
|
||||
// From container.
|
||||
private void OnIsSelectedChanged(DependencyObject sender, DependencyProperty dp)
|
||||
{
|
||||
if (Content is IMailListItem mailItem)
|
||||
{
|
||||
ApplySelectionForModel(mailItem);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySelectionForModel(IMailListItem mailItem)
|
||||
{
|
||||
if (mailItem.IsSelected != IsSelected)
|
||||
{
|
||||
mailItem.IsSelected = IsSelected;
|
||||
WeakReferenceMessenger.Default.Send(new SelectedItemsChangedMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplySelectionForContainer(IMailListItem mailItem)
|
||||
{
|
||||
if (IsSelected != mailItem.IsSelected)
|
||||
{
|
||||
IsSelected = mailItem.IsSelected;
|
||||
}
|
||||
}
|
||||
|
||||
public WinoListView? GetWinoListViewControl()
|
||||
{
|
||||
var expander = GetTemplateChild("ExpanderPart") as Expander;
|
||||
|
||||
if (expander?.Content is ContentPresenter presenter) return VisualTreeHelper.GetChild(presenter, 0) as WinoListView;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Wino.Mail.WinUI.Controls.ListView">
|
||||
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
|
||||
|
||||
<ResourceDictionary>
|
||||
<!-- Thread Mail ListViewItem Style -->
|
||||
<Style x:Key="DefaultThreadListViewItemStyle" TargetType="local:WinoListViewItem">
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}" />
|
||||
<Setter Property="Background" Value="{ThemeResource ListViewItemBackground}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource ListViewItemForeground}" />
|
||||
<Setter Property="TabNavigation" Value="Local" />
|
||||
<Setter Property="IsHoldingEnabled" Value="True" />
|
||||
<Setter Property="Padding" Value="16,0,12,0" />
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
<Setter Property="VerticalContentAlignment" Value="Center" />
|
||||
<Setter Property="MinWidth" Value="{ThemeResource ListViewItemMinWidth}" />
|
||||
<Setter Property="MinHeight" Value="{ThemeResource ListViewItemMinHeight}" />
|
||||
<Setter Property="AllowDrop" Value="False" />
|
||||
<Setter Property="UseSystemFocusVisuals" Value="True" />
|
||||
<Setter Property="FocusVisualMargin" Value="1" />
|
||||
<Setter Property="FocusVisualPrimaryBrush" Value="{ThemeResource ListViewItemFocusVisualPrimaryBrush}" />
|
||||
<Setter Property="FocusVisualPrimaryThickness" Value="2" />
|
||||
<Setter Property="FocusVisualSecondaryBrush" Value="{ThemeResource ListViewItemFocusVisualSecondaryBrush}" />
|
||||
<Setter Property="FocusVisualSecondaryThickness" Value="1" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:WinoListViewItem">
|
||||
<Expander Header="Thread" IsExpanded="{TemplateBinding IsExpanded}">
|
||||
<Expander.Content>
|
||||
<!-- Expandable Content -->
|
||||
<ContentPresenter
|
||||
x:Name="ThreadContent"
|
||||
Margin="{TemplateBinding Padding}"
|
||||
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
|
||||
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}"
|
||||
ContentTransitions="{TemplateBinding ContentTransitions}" />
|
||||
</Expander.Content>
|
||||
</Expander>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<!-- Default Single Mail List View Item Style. -->
|
||||
<Style
|
||||
x:Key="DefaultMailListViewItemStyle"
|
||||
BasedOn="{StaticResource DefaultListViewItemStyle}"
|
||||
TargetType="local:WinoListViewItem" />
|
||||
|
||||
<local:WinoMailItemContainerStyleSelector
|
||||
x:Name="WinoMailItemContainerStyleSelector"
|
||||
MailItemStyle="{StaticResource DefaultMailListViewItemStyle}"
|
||||
ThreadStyle="{StaticResource DefaultThreadListViewItemStyle}" />
|
||||
</ResourceDictionary>
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
|
||||
</ResourceDictionary>
|
||||
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
|
||||
namespace Wino.Mail.WinUI.Controls.ListView;
|
||||
|
||||
public partial class WinoMailItemContainerStyleSelector : StyleSelector
|
||||
{
|
||||
public Style? ThreadStyle { get; set; }
|
||||
public Style? MailItemStyle { get; set; }
|
||||
protected override Style SelectStyleCore(object item, DependencyObject container)
|
||||
{
|
||||
if (item is MailItemViewModel) return MailItemStyle ?? throw new Exception($"Missing style for {nameof(MailItemViewModel)}");
|
||||
if (item is ThreadMailItemViewModel) return ThreadStyle ?? throw new Exception($"Missing style for {nameof(ThreadMailItemViewModel)}");
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Microsoft.UI.Xaml.Controls;
|
||||
using Wino.Mail.ViewModels.Data;
|
||||
|
||||
namespace Wino.Mail.WinUI.Controls.ListView;
|
||||
|
||||
public partial class WinoMailItemTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
public DataTemplate? SingleMailItemTemplate { get; set; }
|
||||
public DataTemplate? ThreadMailItemTemplate { get; set; }
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
if (item is MailItemViewModel)
|
||||
return SingleMailItemTemplate ?? throw new Exception($"Missing template for single mail items.");
|
||||
else if (item is ThreadMailItemViewModel)
|
||||
return ThreadMailItemTemplate ?? throw new Exception($"Missing template for thread mail items.");
|
||||
|
||||
return base.SelectTemplateCore(item, container);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user