Skip to content

Commit

Permalink
Alternating ListBox control
Browse files Browse the repository at this point in the history
  • Loading branch information
macabrett committed Jan 16, 2022
1 parent e306828 commit b7a2237
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 28 deletions.
57 changes: 57 additions & 0 deletions AvaloniaEx/Controls/AlternatingListBox.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
namespace Macabresoft.AvaloniaEx;

using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Media;

/// <summary>
/// A <see cref="ListBox"/> with alternating row colors.
/// </summary>
public sealed class AlternatingListBox : ListBox {
/// <summary>
/// The alternate background property.
/// </summary>
public static readonly StyledProperty<IBrush> AlternateBackgroundProperty =
AvaloniaProperty.Register<AlternatingListBox, IBrush>(nameof(AlternateBackground));

/// <summary>
/// Gets or sets the alternate background color to be used on every other row.
/// </summary>
public IBrush AlternateBackground {
get => this.GetValue(AlternateBackgroundProperty);
set => this.SetValue(AlternateBackgroundProperty, value);
}

/// <inheritdoc />
protected override IItemContainerGenerator CreateItemContainerGenerator() {
return new AlternatingListBoxItemGenerator(this);
}

private sealed class AlternatingListBoxItemGenerator : ItemContainerGenerator<ListBoxItem> {
private readonly AlternatingListBox _owner;
private bool _useAlternateColor;

/// <summary>
/// Initializes a new instance of the <see cref="AlternatingListBoxItemGenerator" /> class.
/// </summary>
/// <param name="owner">The owner.</param>
public AlternatingListBoxItemGenerator(AlternatingListBox owner) : base(owner, ContentControl.ContentProperty, ContentControl.ContentTemplateProperty) {
this._owner = owner;
}

/// <inheritdoc />
protected override IControl CreateContainer(object item) {
var result = base.CreateContainer(item);
if (this._useAlternateColor && result is ListBoxItem listBoxItem) {
result.SetValue(TemplatedControl.BackgroundProperty, this._owner.AlternateBackground);
}

this._useAlternateColor = !this._useAlternateColor;
return result;
}
}
}

1 change: 1 addition & 0 deletions AvaloniaEx/Theme/Accents/Base.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,6 @@
<SolidColorBrush x:Key="DarkYellowBrush" Color="#735D23" />
<SolidColorBrush x:Key="WhiteBrush" Color="{StaticResource SystemBaseHighColor}" />
<SolidColorBrush x:Key="SystemAccentBrush" Color="{StaticResource SystemAccentColor}" />
<SolidColorBrush x:Key="AlternateListBoxItemBackgroundColor" Color="#28FFFFFF" />
</Style.Resources>
</Style>
2 changes: 1 addition & 1 deletion AvaloniaEx/Theme/Base.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/BoxShadows.axaml" />
<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/IconPaths.axaml" />

<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/Controls/AlternatingListBox.axaml" />
<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/Controls/AutoCompleteBox.axaml" />
<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/Controls/Border.axaml" />
<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/Controls/Button.axaml" />
Expand All @@ -26,5 +27,4 @@
<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/Controls/TreeView.axaml" />
<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/Controls/TreeViewItem.axaml" />
<StyleInclude Source="avares://Macabresoft.AvaloniaEx/Theme/Controls/Window.axaml" />

</Styles>
36 changes: 36 additions & 0 deletions AvaloniaEx/Theme/Controls/AlternatingListBox.axaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:avaloniaEx="clr-namespace:Macabresoft.AvaloniaEx">
<Style Selector="avaloniaEx|AlternatingListBox">
<Setter Property="TextBlock.Foreground" Value="{StaticResource SystemControlForegroundBaseHighBrush}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="AlternateBackground" Value="{StaticResource AlternateListBoxItemBackgroundColor}" />
<Setter Property="BorderBrush" Value="{StaticResource SystemControlForegroundBaseHighBrush}" />
<Setter Property="BorderThickness" Value="{StaticResource ListBoxBorderThemeThickness}" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="FontSize" Value="{StaticResource ControlContentThemeFontSize}" />
<Setter Property="Margin" Value="{StaticResource StandardMarginAll}" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="border"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}">
<ScrollViewer Name="PART_ScrollViewer"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}"
AllowAutoHide="{TemplateBinding (ScrollViewer.AllowAutoHide)}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
Margin="{TemplateBinding Padding}"
VirtualizationMode="{TemplateBinding VirtualizationMode}"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter>
</Style>
</Styles>
50 changes: 25 additions & 25 deletions AvaloniaEx/Theme/Controls/ListBoxItem.axaml
Original file line number Diff line number Diff line change
@@ -1,68 +1,68 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style Selector="ListBoxItem">
<Setter Property="Background" Value="{DynamicResource TreeViewItemBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource TreeViewItemBorderBrush}" />
<Setter Property="BorderThickness" Value="{DynamicResource TreeViewItemBorderThemeThickness}" />
<Setter Property="Foreground" Value="{DynamicResource TreeViewItemForeground}" />
<Setter Property="MinHeight" Value="{DynamicResource TreeViewItemMinHeight}" />
<Setter Property="Padding" Value="16,0,0,0" />
<Setter Property="Background" Value="{StaticResource TreeViewItemBackground}" />
<Setter Property="BorderBrush" Value="{StaticResource TreeViewItemBorderBrush}" />
<Setter Property="BorderThickness" Value="{StaticResource TreeViewItemBorderThemeThickness}" />
<Setter Property="Foreground" Value="{StaticResource TreeViewItemForeground}" />
<Setter Property="MinHeight" Value="{StaticResource TreeViewItemMinHeight}" />
<Setter Property="Padding" Value="{StaticResource StandardMarginAll}" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
</Style>

<Style Selector="ListBoxItem /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
<Setter Property="CornerRadius" Value="{StaticResource ControlCornerRadius}" />
</Style>

<!-- Disabled State -->
<Style Selector="ListBoxItem:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource TreeViewItemBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{DynamicResource TreeViewItemBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TreeViewItemForegroundDisabled}" />
<Setter Property="Background" Value="{StaticResource TreeViewItemBackgroundDisabled}" />
<Setter Property="BorderBrush" Value="{StaticResource TreeViewItemBorderBrushDisabled}" />
<Setter Property="TextBlock.Foreground" Value="{StaticResource TreeViewItemForegroundDisabled}" />
</Style>

<!-- PointerOver State -->
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource TreeViewItemBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource TreeViewItemBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TreeViewItemForegroundPointerOver}" />
<Setter Property="Background" Value="{StaticResource TreeViewItemBackgroundPointerOver}" />
<Setter Property="BorderBrush" Value="{StaticResource TreeViewItemBorderBrushPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{StaticResource TreeViewItemForegroundPointerOver}" />
</Style>

<!-- Pressed State -->
<Style Selector="ListBoxItem:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource TreeViewItemBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource TreeViewItemBorderBrushPressed}" />
<Setter Property="Background" Value="{StaticResource TreeViewItemBackgroundPressed}" />
<Setter Property="BorderBrush" Value="{StaticResource TreeViewItemBorderBrushPressed}" />
</Style>
<Style Selector="ListBoxItem:pressed /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TreeViewItemForegroundPressed}" />
<Setter Property="TextBlock.Foreground" Value="{StaticResource TreeViewItemForegroundPressed}" />
</Style>

<!-- Selected State -->
<Style Selector="ListBoxItem:selected /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource TreeViewItemBackgroundSelected}" />
<Setter Property="BorderBrush" Value="{DynamicResource TreeViewItemBorderBrushSelected}" />
<Setter Property="Background" Value="{StaticResource TreeViewItemBackgroundSelected}" />
<Setter Property="BorderBrush" Value="{StaticResource TreeViewItemBorderBrushSelected}" />
</Style>
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TreeViewItemForegroundSelected}" />
<Setter Property="TextBlock.Foreground" Value="{StaticResource TreeViewItemForegroundSelected}" />
</Style>

<!-- Selected PointerOver State -->
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource TreeViewItemBackgroundSelectedPointerOver}" />
<Setter Property="BorderBrush" Value="{DynamicResource TreeViewItemBorderBrushSelectedPointerOver}" />
<Setter Property="Background" Value="{StaticResource TreeViewItemBackgroundSelectedPointerOver}" />
<Setter Property="BorderBrush" Value="{StaticResource TreeViewItemBorderBrushSelectedPointerOver}" />
</Style>
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TreeViewItemForegroundSelectedPointerOver}" />
<Setter Property="TextBlock.Foreground" Value="{StaticResource TreeViewItemForegroundSelectedPointerOver}" />
</Style>

<!-- Selected Pressed State -->
<Style Selector="ListBoxItem:selected:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource TreeViewItemBackgroundSelectedPressed}" />
<Setter Property="BorderBrush" Value="{DynamicResource TreeViewItemBorderBrushSelectedPressed}" />
<Setter Property="Background" Value="{StaticResource TreeViewItemBackgroundSelectedPressed}" />
<Setter Property="BorderBrush" Value="{StaticResource TreeViewItemBorderBrushSelectedPressed}" />
</Style>
<Style Selector="ListBoxItem:selected:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource TreeViewItemForegroundSelectedPressed}" />
<Setter Property="TextBlock.Foreground" Value="{StaticResource TreeViewItemForegroundSelectedPressed}" />
</Style>


Expand Down
4 changes: 2 additions & 2 deletions Sample/Views/MainWindow.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@
<TextBlock Classes="Label"
Text="A Curious List"
Foreground="{StaticResource YellowBrush}"/>
<ListBox Grid.Row="1"
Items="{Binding List}" />
<avaloniaEx:AlternatingListBox Grid.Row="1"
Items="{Binding List}" />
</Grid>
</Border>
</Grid>
Expand Down

0 comments on commit b7a2237

Please sign in to comment.