Skip to content

Please enhance the close button of TabItem #1402

@northgisdev

Description

@northgisdev

Is your feature request related to a problem? Please describe

Please implement a close button for TabItem, just like the tags on Chrome or EDGE browsers.

Describe the solution you'd like

I have implemented a close button for TabItem myself. If there is a better method, please update the functionality. This is the code I implemented myself. Firstly, add a class. Then update the style. Add Grid and place the close button in the second column.

Describe alternatives you've considered

public static class TabItemCloseBehavior
{
public static readonly DependencyProperty IsCloseButtonEnabledProperty =
DependencyProperty.RegisterAttached(
"IsCloseButtonEnabled",
typeof(bool),
typeof(TabItemCloseBehavior),
new UIPropertyMetadata(false, OnIsCloseButtonEnabledChanged));

/// <summary>Helper for getting <see cref="IsCloseButtonEnabledProperty"/> from <paramref name="obj"/>.</summary>
/// <param name="obj"><see cref="DependencyObject"/> to read <see cref="IsCloseButtonEnabledProperty"/> from.</param>
/// <returns>IsCloseButtonEnabled property value.</returns>
[AttachedPropertyBrowsableForType(typeof(DependencyObject))]
public static bool GetIsCloseButtonEnabled(DependencyObject obj)
{
    return (bool)obj.GetValue(IsCloseButtonEnabledProperty);
}

/// <summary>Helper for setting <see cref="IsCloseButtonEnabledProperty"/> on <paramref name="obj"/>.</summary>
/// <param name="obj"><see cref="DependencyObject"/> to set <see cref="IsCloseButtonEnabledProperty"/> on.</param>
/// <param name="value">IsCloseButtonEnabled property value.</param>
public static void SetIsCloseButtonEnabled(DependencyObject obj, bool value)
{
    obj.SetValue(IsCloseButtonEnabledProperty, value);
}

private static void OnIsCloseButtonEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    if (d is TabItem tabItem && e.NewValue is bool newValue && newValue)
    {
        tabItem.Loaded += TabItem_Loaded;
    }
}

private static void TabItem_Loaded(object sender, RoutedEventArgs e)
{
    if (sender is TabItem tabItem)
    {
        // Manually add a close button
        var closeButton = new Wpf.Ui.Controls.Button
        {
            Width = 16,
            Height = 16,
            Margin = new Thickness(8, 0, 0, 0),
            Padding = new Thickness(0, 0, 0, 0),
            HorizontalAlignment = HorizontalAlignment.Center,
            VerticalAlignment = VerticalAlignment.Center,
            Background = Brushes.Transparent,
            BorderBrush = Brushes.Transparent,
            Cursor = Cursors.Hand,
            Focusable = false
        };
        var path = new Path
        {
            Data = new GeometryGroup
            {
                Children =
                [
                    new LineGeometry(new Point(0, 0), new Point(8, 8)),
                    new LineGeometry(new Point(8, 0), new Point(0, 8))
                ]
            },
            Style = (Style)Application.Current.FindResource("CloseIconStyle"), // 使用动态资源
            StrokeThickness = 1.5
        };
        closeButton.Content = path;

        closeButton.Click += CloseButton_Click;

        // Find the template root Grid for TabItem
        if (tabItem.Template?.FindName("headRoot", tabItem) is Grid grid)
        {
            // Find the second column (position of the close button)
            ColumnDefinition closeButtonColumn = grid.ColumnDefinitions[1];

            // Add the button to the TabItem template and ensure it appears in the second column
            Grid.SetColumn(closeButton, 1);
            _ = grid.Children.Add(closeButton);
        }
    }
}

private static void CloseButton_Click(object sender, RoutedEventArgs e)
{
    if (sender is Button button)
    {
        TabItem? tabItem = FindAncestor<TabItem>(button);
        if (tabItem != null)
        {
            if (ItemsControl.ItemsControlFromItemContainer(tabItem) is System.Windows.Controls.TabControl tabControl && tabItem != null)
            {
                tabControl.Items.Remove(tabItem);
            }
        }
    }
}

private static T? FindAncestor<T>(DependencyObject current)
    where T : DependencyObject
{
    do
    {
        if (current is T ancestor)
        {
            return ancestor;
        }

        current = VisualTreeHelper.GetParent(current);
    }
    while (current != null);
    return null;
}

}

Additional context

Image

Image

Image

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions