Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding SelectionMode to TabStrip #18109

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 14 additions & 5 deletions samples/ControlCatalog/Pages/TabStripPage.xaml
Original file line number Diff line number Diff line change
@@ -2,14 +2,22 @@
x:Class="ControlCatalog.Pages.TabStripPage"
xmlns="https://github.com/avaloniaui"
xmlns:viewModels="using:ControlCatalog.ViewModels"
x:DataType="viewModels:TabControlPageViewModel">
<StackPanel Orientation="Vertical" Spacing="4">
x:DataType="viewModels:TabStripPageViewModel">
<DockPanel>
<StackPanel DockPanel.Dock="Top" Orientation="Vertical" Spacing="4">
<TextBlock Classes="h2">A control which displays a selectable strip of tabs</TextBlock>

<Separator Margin="0 16"/>

</StackPanel>
<StackPanel DockPanel.Dock="Right" Margin="16 0">
<TextBlock Classes="h2" xml:space="preserve" Margin="0 4">Modifies the SelectionModes of
the XAML defined Tabstrip:</TextBlock>
<CheckBox IsChecked="{Binding Multiple}">Multiple</CheckBox>
<CheckBox IsChecked="{Binding Toggle}">Toggle</CheckBox>
<CheckBox IsChecked="{Binding AlwaysSelected}">AlwaysSelected</CheckBox>
</StackPanel>
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Defined in XAML</TextBlock>
<TabStrip>
<TabStrip SelectionMode="{Binding SelectionMode^}">
<TabStripItem>Item 1</TabStripItem>
<TabStripItem>Item 2</TabStripItem>
<TabStripItem IsEnabled="False">Disabled</TabStripItem>
@@ -31,4 +39,5 @@
</TabStrip.ItemTemplate>
</TabStrip>
</StackPanel>
</DockPanel>
</UserControl>
2 changes: 1 addition & 1 deletion samples/ControlCatalog/Pages/TabStripPage.xaml.cs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ public TabStripPage()
{
InitializeComponent();

DataContext = new TabControlPageViewModel
DataContext = new TabStripPageViewModel
{
Tabs = new []
{
46 changes: 46 additions & 0 deletions samples/ControlCatalog/ViewModels/TabStripPageViewModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using Avalonia.Controls;
using MiniMvvm;

namespace ControlCatalog.ViewModels;

public class TabStripPageViewModel : ViewModelBase
{
private bool _multiple;
private bool _toggle;
private bool _alwaysSelected;
private IObservable<SelectionMode> _selectionMode;

public TabControlPageViewModelItem[]? Tabs { get; set; }
public IObservable<SelectionMode> SelectionMode => _selectionMode;

public TabStripPageViewModel()
{
_selectionMode = this.WhenAnyValue(
x => x.Multiple,
x => x.Toggle,
x => x.AlwaysSelected,
(m, t, a) =>
(m ? Avalonia.Controls.SelectionMode.Multiple : 0) |
(t ? Avalonia.Controls.SelectionMode.Toggle : 0) |
(a ? Avalonia.Controls.SelectionMode.AlwaysSelected : 0));
}

public bool Multiple
{
get => _multiple;
set => this.RaiseAndSetIfChanged(ref _multiple, value);
}

public bool Toggle
{
get => _toggle;
set => this.RaiseAndSetIfChanged(ref _toggle, value);
}

public bool AlwaysSelected
{
get => _alwaysSelected;
set => this.RaiseAndSetIfChanged(ref _alwaysSelected, value);
}
}
24 changes: 23 additions & 1 deletion src/Avalonia.Controls/Primitives/TabStrip.cs
Original file line number Diff line number Diff line change
@@ -9,9 +9,31 @@ public class TabStrip : SelectingItemsControl
private static readonly FuncTemplate<Panel?> DefaultPanel =
new(() => new WrapPanel { Orientation = Orientation.Horizontal });

/// <summary>
/// Defines the <see cref="SelectionMode"/> property.
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1010",
Justification = "This property is owned by SelectingItemsControl, but protected there. TabStrip changes its visibility.")]
public static readonly new StyledProperty<SelectionMode> SelectionModeProperty =
SelectingItemsControl.SelectionModeProperty;

/// <summary>
/// Gets or sets the selection mode.
/// </summary>
/// <remarks>
/// Note that the selection mode only applies to selections made via user interaction.
/// Multiple selections can be made programmatically regardless of the value of this property.
/// </remarks>
[System.Diagnostics.CodeAnalysis.SuppressMessage("AvaloniaProperty", "AVP1012",
Justification = "This property is owned by SelectingItemsControl, but protected there. TabStrip changes its visibility.")]
public new SelectionMode SelectionMode
{
get => base.SelectionMode;
set => base.SelectionMode = value;
}

static TabStrip()
{
SelectionModeProperty.OverrideDefaultValue<TabStrip>(SelectionMode.AlwaysSelected);
FocusableProperty.OverrideDefaultValue(typeof(TabStrip), false);
ItemsPanelProperty.OverrideDefaultValue<TabStrip>(DefaultPanel);
}
43 changes: 3 additions & 40 deletions tests/Avalonia.Controls.UnitTests/Primitives/TabStripTests.cs
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
using System.Collections.ObjectModel;
using System.Linq;
using Moq;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.LogicalTree;
using Xunit;

namespace Avalonia.Controls.UnitTests.Primitives
{
public class TabStripTests
{
[Fact]
public void First_Tab_Should_Be_Selected_By_Default()
public void First_Tab_Should_Not_Be_Selected_By_Default()
{
var target = new TabStrip
{
@@ -32,8 +28,8 @@ public void First_Tab_Should_Be_Selected_By_Default()

target.ApplyTemplate();

Assert.Equal(0, target.SelectedIndex);
Assert.Same(target.Items[0], target.SelectedItem);
Assert.Equal(-1, target.SelectedIndex);
Assert.Same(null, target.SelectedItem);
Comment on lines +31 to +32
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, we can't change default behavior.
TabStrip.SelectionMode default should be changed to match old behavior, even if it's different from ListBox.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likely, you only need to revert SelectionModeProperty.OverrideDefaultValue<TabStrip>(SelectionMode.AlwaysSelected); line.

}

[Fact]
@@ -62,39 +58,6 @@ public void Setting_SelectedItem_Should_Set_Selection()
Assert.Same(target.Items[1], target.SelectedItem);
}

[Fact]
public void Removing_Selected_Should_Select_First()
{
var target = new TabStrip
{
Template = new FuncControlTemplate<TabStrip>(CreateTabStripTemplate),
Items =
{
new TabItem
{
Name = "first"
},
new TabItem
{
Name = "second"
},
new TabItem
{
Name = "3rd"
},
}
};

target.ApplyTemplate();
target.SelectedItem = target.Items[1];
Assert.Same(target.Items[1], target.SelectedItem);
target.Items.RemoveAt(1);

Assert.Equal(0, target.SelectedIndex);
Assert.Same(target.Items[0], target.SelectedItem);
Assert.Same("first", ((TabItem)target.SelectedItem).Name);
}

private Control CreateTabStripTemplate(TabStrip parent, INameScope scope)
{
return new ItemsPresenter