Tabalonia

repository·main·Indexed 42 days ago

https://github.com/egorozh/tabalonia

An Avalonia port of Draggablz that provides draggable, detachable, and dockable tab items. It enables Chrome-style interactions, allowing users to reorder tabs, tear them off into floating windows, or dock them into other windows using the TabsControl.

Tokens
2.7K
Snippets
7
Records
8
Agent score
4%

What's inside Tabalonia

  1. Install Tabalonia via NuGet

    main

    Install the Tabalonia library as a NuGet package to enable draggable, detachable, and dockable tabs in your Avalonia application.

    Install-Package Tabalonia
    # Or
    dotnet add package Tabalonia
  2. Restyle Tabalonia using Brush Resources

    main

    Instead of re-templating, you can restyle the CustomTheme by overriding specific brush resources in your App.axaml.

    ```xml
    <Application.Resources>
        <ResourceDictionary>
            <ResourceDictionary.ThemeDictionaries>
                <ResourceDictionary x:Key="Dark">
                    <SolidColorBrush x:Key="SelectedTabItemBackgroundBrush" Color="#1E1E2E" />
                </ResourceDictionary>
            </ResourceDictionary.ThemeDictionaries>
        </ResourceDictionary>
    </Application.Resources>

    Full list of keys is available in Themes/Custom/Brushes.axaml.

  3. Configure Tabalonia themes in App.axaml

    main

    To use Tabalonia, you must add a theme to your App.axaml. You can choose between the CustomTheme (with light/dark variants) or the FluentTheme (Fluent-styled variant).

    <!-- Using CustomTheme -->
    <Application xmlns="https://github.com/avaloniaui"
                 xmlns:custom="clr-namespace:Tabalonia.Themes.Custom;assembly=Tabalonia">
        <Application.Styles>
            <FluentTheme />
            <custom:CustomTheme />
        </Application.Styles>
    </Application>
    
    <!-- Using FluentTheme variant -->
    <Application xmlns="https://github.com/avaloniaui"
                 xmlns:fluent="clr-namespace:Tabalonia.Themes.Fluent;assembly=Tabalonia">
        <Application.Styles>
            <fluent:FluentTheme />
        </Application.Styles>
    </Application>
  4. Use TabsControl in Avalonia

    main

    The TabsControl is used similarly to a standard Avalonia TabControl.

    Important: The ItemsSource must implement IList (such as ObservableCollection<T>) because adding, closing, reordering, and dragging tabs between windows directly mutates the collection.

    <Window xmlns:controls="clr-namespace:Tabalonia.Controls;assembly=Tabalonia">
    
        <controls:TabsControl ItemsSource="{Binding TabItems}"
                              NewItemFactory="{Binding NewItemFactory}"
                              FixedHeaderCount="1">
            <TabControl.ItemTemplate>
                <DataTemplate DataType="vm:TabItemViewModel">
                    <TextBlock Text="{Binding Header}" />
                </DataTemplate>
            </TabControl.ItemTemplate>
    
            <TabControl.ContentTemplate>
                <DataTemplate DataType="vm:TabItemViewModel">
                    <TextBlock Text="{Binding SimpleContent}" />
                </DataTemplate>
            </TabControl.ContentTemplate>
        </controls:TabsControl>
    
    </Window>
  5. Configure tab detaching and docking

    main

    Tabalonia allows tabs to be torn off into new windows or docked into other TabsControl instances.

    ```csharp
    // Customizing the window created when a tab is torn off
    tabsControl.DetachedWindowFactory = tabs => new MyToolWindow { Content = tabs };

    Properties Reference

    PropertyTypeDefaultDescription
    EnableTabDetachingbooltrueAllows dragging a tab out of the strip into a new floating window
    EnableTabAttachingbooltrueAllows this strip to give away and accept tabs dragged from other TabsControls
    DetachTriggerDistancedouble32How far (px) the pointer must leave the strip before the tab tears off
    DetachedWindowFactoryFunc<TabsControl, Window>?nullCreates the host window for a detached tab; by default the source window's size, background and decorations are cloned
  6. Configure Tab strip appearance

    main

    Use these properties on TabsControl to adjust the visual layout of the tab strip:

    PropertyTypeDefaultDescription
    TabItemWidthdouble140Maximum tab width; tabs shrink evenly when the strip runs out of space
    AdjacentHeaderItemOffsetdouble0Horizontal offset between neighbouring tabs (negative values overlap them)
    FixedHeaderCountint0Number of leading tabs that are pinned: they can't be dragged, closed or displaced
    LeftContentobject?nullArbitrary content rendered to the left of the tab strip
    RightContentobject?nullArbitrary content rendered to the right of the tab strip
  7. Manage adding and closing tabs

    main

    Tabalonia provides built-in mechanisms for adding and closing tabs. You can control visibility and provide factories for new items.

    ```csharp
    // Handling tab closing events to prevent closing unsaved documents
    tabs.TabClosing += (_, e) =>
    {
        if (e.Item is DocumentViewModel { IsDirty: true })
            e.Cancel = true; // keep the tab open
    };
    
    tabs.TabClosed += (_, e) => Console.WriteLine($"Closed: {e.Item}");
    
    // Prevent the window from closing when the last tab is closed
    tabs.LastTabClosedAction = (_, e) => { /* e.Window stays open */ };

    Members Reference

    MemberTypeDescription
    ShowDefaultAddButtonboolShows the built-in "+" button after the last tab (Default: true)
    ShowDefaultCloseButtonboolShows the "×" button on each tab (except fixed ones) (Default: true)
    NewItemFactoryFunc<object>?Creates the model for a new tab when the add button is clicked
    NewItemAsyncFactoryFunc<Task<object>>?Async variant; takes precedence over NewItemFactory
    AddItemCommandICommand(Read-only) Adds a tab via the factory — bind it from your own buttons
    CloseItemCommandICommand(Read-only) Closes the tab passed as the command parameter (DragTabItem)
    TabClosingEventHandler<TabClosingEventArgs>?Raised before a tab closes; set e.Cancel = true to keep it open
    TabClosedEventHandler<TabClosedEventArgs>?Raised after a tab closed; e.Item is the removed model
    LastTabClosedActionEventHandler<CloseLastTabEventArgs>?Action taken when the last tab is removed; default closes the window (e.Window)
  8. Configure window drag thumbs

    main

    The empty areas in the tab strip act as window-drag handles (double-click to restore/maximize). This is useful when using ExtendClientAreaToDecorationsHint="True".

    | Property | Default | Description |
    |---|---|---|
    | `LeftThumbWidth` | `80` (macOS), `4` (elsewhere) | Width of the drag area before the first tab |
    | `RightThumbWidth` | `160` (Windows), `50` (elsewhere) | Width of the drag area after the add button |