Ursa.Avalonia
Ursa.Avalonia copied to clipboard
TreeComboBox need supporting multiple-selection
At the beginning of the new year, I wish the request could be added into roadmap. Only supporting single-selection is a little unfair to this control with so wonderful functionalities.
Is there any progress? The multi-select cascading selector control is very necessary for selecting individual stores or stores in a certain area within an organizational structure. Many web component libraries have similar controls. My capabilities are limited to do it. and I'm looking forward to seeing this suggestion realized in the 2.0 release.
BLACK MAGIC
workaround:
Item VM:
public class ItemVM(RawItem item, Action<ItemVM> isCheckedChanged) : ViewModelBase
{
private bool isChecked;
private bool isExpanded = true;
public bool IsChecked
{
get => isChecked;
set
{
this.RaiseAndSetIfChanged(ref isChecked, value);
isCheckedChanged(this);
}
}
public bool IsExpanded
{
get => isExpanded;
set => this.RaiseAndSetIfChanged(ref isExpanded, value);
}
public ObservableCollection<ItemVM> Children { get; } = [];
}
View VM:
public class ViewVM : ViewModelBase
{
public ObservableCollection<ItemVM> ItemRoots { get; private set; } = [];
public ObservableCollection<ItemVM> SelectedItems { get; } = [];
public void LoadItems()
{
var newItems = GetItems();
ItemRoots = new(newItems.Select(item => new ItemVM(item, ItemCheckedChanged)));
this.RaisePropertyChanged(nameof(ItemRoots));
}
private void ItemCheckedChanged(ItemVM item)
{
var exists = SelectedItems.FirstOrDefault(itemIn => itemIn.Key == item.Key);
if (item.IsChecked && exists == null)
{
SelectedItems.Add(item);
}
else if (exists != null)
{
SelectedItems.Remove(exists);
}
}
public void RemoveSelection(IDataContextProvider obj)
{
if (obj.DataContext is ItemVM item)
{
item.IsChecked = false;
}
}
}
In axaml:
<u:TreeComboBox ItemsSource="{Binding ItemRoots}">
<u:TreeComboBox.Styles>
<Style Selector="u|TreeComboBox /template/ TextBlock#PlaceholderTextBlock">
<Setter Property="IsVisible" Value="{Binding !SelectedItems.Count}" />
</Style>
</u:TreeComboBox.Styles>
<u:TreeComboBox.SelectedItemTemplate>
<DataTemplate>
<u:MultiComboBoxSelectedItemList x:DataType="vm:ViewVM"
DataContext="{Binding $parent[u:TreeComboBox].DataContext}"
ItemsSource="{Binding SelectedItems}"
RemoveCommand="{Binding RemoveSelection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Background="Transparent" Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<u:MultiComboBoxSelectedItemList.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</u:MultiComboBoxSelectedItemList.ItemTemplate>
</u:MultiComboBoxSelectedItemList>
</DataTemplate>
</u:TreeComboBox.SelectedItemTemplate>
<u:TreeComboBox.ItemContainerTheme>
<ControlTheme x:DataType="vm:ItemVM"
BasedOn="{StaticResource {x:Type u:TreeComboBoxItem}}"
TargetType="u:TreeComboBoxItem">
<!-- ** MAGIC HERE ** -->
<!-- Not use TreeComboBox selection -->
<Setter Property="IsSelectable" Value="False" />
<!-- Multiple selection has implement in based control but protected -->
<Setter Property="SelectingItemsControl.IsSelected" Value="{Binding IsChecked}" />
<Setter Property="IsExpanded" Value="{Binding IsExpanded}" />
</ControlTheme>
</u:TreeComboBox.ItemContainerTheme>
<u:TreeComboBox.ItemTemplate>
<TreeDataTemplate ItemsSource="{Binding Children}">
<CheckBox VerticalAlignment="Center" Content="{Binding Name}"
IsChecked="{Binding IsChecked}"
UseLayoutRounding="True" />
</TreeDataTemplate>
</u:TreeComboBox.ItemTemplate>
</u:TreeComboBox>