Files
AtomUI/docs/release-notes/6.1.3-api-changes.md
T

15 KiB

AtomUI 6.1.3 API Change Examples

This document supplements the main 6.1.3 release notes with the most important breaking API changes and migration examples from 6.1.2. For the authoritative release entries, see the repository root CHANGELOG.md and CHANGELOG.zh-CN.md.

The Avalonia dependency upgrade from 12.1.0 to 12.1.1 does not require AtomUI applications to change source code by itself. This page covers public contract changes in the same AtomUI release across Theme, Localization, Upload, Timeline, Tag, and Separator.

Chinese version: 6.1.3 API 变更示例.

Quick Reference

Area 6.1.2 6.1.3
Theme algorithms String algorithm IDs ThemeAlgorithm enum
Theme control package registration Register token descriptors and theme providers separately Generated ControlPackageRegistration
Localization LanguageVariant, LanguageProvider, ThemeManager language state LanguageTag, XLIFF 2.1 catalogs, ILanguageManager
Upload file filters Accepts string collection AllowedFileTypes / FilePickerFileType
Upload click and drop input Upload.IsOpenFileDialogOnClick, UploadDefaultDropArea.FilesDropped UploadDropZone and InputBatchCompleted
Upload file content URI and fixed-size UploadFileInfo constructors IUploadFileSource opens file streams on demand
Timeline placement Left / Right Start / End, plus Orientation
Tag appearance IsBordered TagVariant
Separator size SizeType CustomizableSizeType

Theme Compilation and Registration Migration

Algorithm strings are now enum values

ThemeConfigBuilder.WithAlgorithms and ControlThemeConfigBuilder.WithAlgorithms no longer accept strings. Algorithm attributes, descriptors, and runtime state now use ThemeAlgorithm.

6.1.2

var themeConfig = new ThemeConfigBuilder()
    .WithAlgorithms("Default", "Dark")
    .Build();

6.1.3

using AtomUI.Theme.Algorithms;
using AtomUI.Theme.Configuration;

var themeConfig = new ThemeConfigBuilder()
    .WithAlgorithms(ThemeAlgorithm.Default, ThemeAlgorithm.Dark)
    .Build();

Custom algorithm declarations must migrate too:

// 6.1.2
[ThemeAlgorithmAttribute("Dark", 1, ThemeAppearanceEffect.Dark)]

// 6.1.3
[ThemeAlgorithmAttribute(ThemeAlgorithm.Dark, 1, ThemeAppearanceEffect.Dark)]

ThemeAlgorithmAttribute.Id and ThemeAlgorithmDescriptor.Id have been replaced by Algorithm. The current algorithm set is closed over Default, Dark, and Compact; arbitrary string algorithm IDs are no longer supported.

Control packages register as one package

Custom control packages should no longer call IThemeManagerBuilder.AddControlToken() and AddControlThemesProvider() separately. Token descriptors, theme asset descriptors, and the theme provider must be registered as one ControlPackageRegistration during Application.UseAtomUI(...), before the theme schema freezes.

6.1.2

application.UseAtomUI(themeBuilder =>
{
    foreach (var descriptor in MyGeneratedThemeSchema.GetControls())
    {
        themeBuilder.AddControlToken(descriptor);
    }

    themeBuilder.AddControlThemesProvider(new MyControlThemesProvider());
});

6.1.3

application.UseAtomUI(builder =>
{
    builder.AddControlPackage(new ControlPackageRegistration(
        id: "MyCompany.Controls",
        controls: MyGeneratedThemeSchema.GetControls(),
        themeAssets: MyGeneratedThemeAssetManifest.GetDescriptors(),
        controlThemesProvider: new MyControlThemesProvider()));
});

The generated type names in the example are owned by the custom control package. Real projects should use the descriptors and asset manifests emitted by AtomUI Generator. Do not scan assemblies or AXAML files at runtime.

Theme definition resolvers should also be registered from the root builder stage:

application.UseAtomUI(builder =>
{
    builder.AddThemeDefinitionResolver(new MyThemeDefinitionResolver());
    builder.UseDesktopControls();
});

Theme schema, control identity, token schema, and theme asset manifests are frozen before the first theme snapshot is compiled. Applications cannot append control packages or mutate committed ThemeConfig collections after startup.

Generated Localization Catalog Migration

Removed legacy language APIs

The following types and entry points have been removed:

LanguageCode
LanguageVariant
LanguageVariantTypeConverter
LanguageProvider
ILanguageProvider
LanguageProviderAttribute
LanguageProviderPool
IThemeManagerBuilder.AddLanguageProviders()
IThemeManagerBuilder.WithDefaultLanguageVariant()

Language state is no longer owned by ThemeManager. Applications should use LanguageTag, ILanguageManager, ILocalizer, and root-level IAtomUIBuilder.UseLanguages().

Configure supported languages

6.1.2

application.UseAtomUI(themeBuilder =>
{
    themeBuilder.WithDefaultLanguageVariant(LanguageVariant.zh_CN);
    themeBuilder.AddLanguageProviders(new MyZhCnLanguageProvider());
    themeBuilder.UseDesktopControls();
});

6.1.3

using AtomUI.Localization;

application.UseAtomUI(builder =>
{
    builder.UseLanguages(
        defaultLanguage: LanguageTags.ZhCN,
        supportedLanguages:
        [
            LanguageTags.EnUS,
            LanguageTags.ZhCN,
            LanguageTags.ZhTW
        ]);

    builder.UseDesktopControls();
});

Application catalogs, component catalogs, and static language packages are generated and registered from XLIFF 2.1 inputs. UseLanguages() only declares the default language and the application-supported language set; it does not accept providers or language package instances.

Change language at runtime

6.1.2

themeManager.LanguageVariant = LanguageVariant.zh_TW;

6.1.3

var languageManager = application.GetLanguageManager()
    ?? throw new InvalidOperationException("AtomUI localization is not initialized.");

languageManager.ChangeLanguage(LanguageTags.ZhTW);

Plain C# and ViewModel localization should use ILocalizer:

var localizer = application.GetLocalizer()
    ?? throw new InvalidOperationException("AtomUI localization is not initialized.");

string title = localizer.Get(SettingsLangResourceKind.Title);

Existing XAML markup extension usage is preserved:

<TextBlock Text="{atom:DatePickerLangResource Today}" />

Catalog identity changes

Catalog enum member names and XLIFF unit id values now form the stable resource key. LanguageCatalogUnitDescriptor.Id and Name have converged into Key, and production catalog ContractVersion is now 2.

Applications, components, and static language packages must be rebuilt together. Do not mix 6.1.2 numeric-ID catalog assemblies or language packages with 6.1.3 key-based catalogs. Existing third-party language packages should be re-exported, translated, and repackaged from the new authoritative en-US.xlf files.

Upload Input Contract Migration

Accepts is now AllowedFileTypes

Accepts string patterns and MIME entries have been replaced by Avalonia Storage API FilePickerFileType.

6.1.2

upload.Accepts = ["*.png", "*.jpg", "image/png", "image/jpeg"];

6.1.3

using Avalonia.Platform.Storage;

upload.AllowedFileTypes =
[
    new FilePickerFileType("Images")
    {
        Patterns = ["*.png", "*.jpg", "*.jpeg"],
        MimeTypes = ["image/png", "image/jpeg"]
    }
];

The same AllowedFileTypes collection is used by the picker filter and by Upload admission. Programmatic input, expanded directory input, and drop input are validated against the same rules.

Click-to-select moves to UploadDropZone

Upload.IsOpenFileDialogOnClick has been removed. Click selection is owned by the composable UploadDropZone, and SourceKind decides whether the zone opens a file picker or a directory picker.

6.1.2

<atom:Upload
    IsOpenFileDialogOnClick="True"
    Files="{Binding Attachments}" />

6.1.3

<atom:Upload Files="{Binding Attachments}">
    <atom:UploadDropZone
        IsOpenFileDialogOnClick="True"
        SourceKind="Files">
        <TextBlock Text="Click or drop files" />
    </atom:UploadDropZone>
</atom:Upload>

Use SourceKind="Directories" for directory selection. Set IsOpenFileDialogOnClick="False" when a zone should accept drops only.

Drop events are now input batch results

UploadDefaultDropArea.FilesDropped, FilesDroppedEvent, and UploadFilesDroppedEventArgs have been removed. UploadDefaultDropArea now owns only the default visuals, and UploadDropZone is the only DragDrop input surface.

Do not handle raw IStorageFile collections from the drop area. Use Upload.InputBatchCompleted when application code needs input results, rejection reasons, or batch failures:

private void HandleInputBatchCompleted(
    object? sender,
    UploadInputBatchCompletedEventArgs e)
{
    if (e.Status == UploadInputBatchStatus.Failed)
    {
        LogInputFailure(e.BatchId, e.FailureReason);
        return;
    }

    foreach (var rejected in e.RejectedItems)
    {
        LogRejectedFile(rejected.Name, rejected.Reason, rejected.Message);
    }
}
<atom:Upload
    Files="{Binding Attachments}"
    InputBatchCompleted="HandleInputBatchCompleted">
    <atom:UploadDropZone DirectoryDropMode="RecursiveFiles">
        <atom:UploadDefaultDropArea />
    </atom:UploadDropZone>
</atom:Upload>

UploadFileInfo now uses openable file sources

UploadFileInfo no longer assumes that every file has an accessible local URI, fixed size, or repeatable file path. Callers must provide an IUploadFileSource; each OpenReadAsync() call should return a fresh readable stream.

6.1.2

var file = new UploadFileInfo(
    name: "report.pdf",
    filePath: new Uri(filePath),
    size: new FileInfo(filePath).Length);

6.1.3

sealed class LocalUploadFileSource(string filePath) : IUploadFileSource
{
    public ValueTask<Stream> OpenReadAsync(
        CancellationToken cancellationToken = default)
    {
        cancellationToken.ThrowIfCancellationRequested();
        return ValueTask.FromResult<Stream>(File.OpenRead(filePath));
    }
}

var fileInfo = new FileInfo(filePath);
var file = new UploadFileInfo(
    name: fileInfo.Name,
    source: new LocalUploadFileSource(filePath),
    path: new Uri(filePath),
    size: fileInfo.Length,
    contentType: "application/pdf");

await upload.EnqueueFilesAsync([file]);

If the source owns a temporary file, StorageItem lease, or other disposable resource, ownership is transferred to Upload until the upload exits, the file is removed, or the control is disposed.

Custom admission policies

Implement IUploadAdmissionPolicy when application-specific validation is needed. Return decisions through the factory methods:

sealed class AttachmentAdmissionPolicy : IUploadAdmissionPolicy
{
    public ValueTask<UploadAdmissionDecision> EvaluateAsync(
        UploadAdmissionContext context,
        CancellationToken cancellationToken = default)
    {
        return context.File.Size > 10 * 1024 * 1024
            ? ValueTask.FromResult(UploadAdmissionDecision.Reject(
                "file-too-large",
                "The file exceeds the 10 MB limit."))
            : ValueTask.FromResult(UploadAdmissionDecision.Accept());
    }
}
<atom:Upload
    AdmissionPolicy="{Binding AttachmentAdmissionPolicy}"
    CountOverflowBehavior="RejectExcess"
    MaxCount="5" />

Timeline Logical Direction Migration

TimelineMode.Left and TimelineMode.Right have been replaced by logical Start and End values to support RTL and horizontal layouts.

6.1.2 6.1.3
TimelineMode.Left TimelineMode.Start
TimelineMode.Right TimelineMode.End
IndicatorLeftModeMargin IndicatorStartModeMargin
IndicatorRightModeMargin IndicatorEndModeMargin

6.1.2

<atom:Timeline Mode="Left" />

6.1.3

<atom:Timeline
    Mode="Start"
    Orientation="Vertical" />

Horizontal timelines use the same logical placement model:

<atom:Timeline
    Mode="Alternate"
    Orientation="Horizontal" />

Orientation still defaults to Vertical. Custom theme or token overrides should migrate to the Start/End resource names too.

Tag Variant and Checkable Tag Migration

IsBordered is now TagVariant

Tag.IsBordered has been removed. The new Variant supports Filled, Solid, and Outlined; the default is Filled.

6.1.2

<atom:Tag
    Text="Release"
    IsBordered="True" />

6.1.3

<atom:Tag
    Text="Release"
    Variant="Outlined" />

There is no exact compatibility mode for the old IsBordered="False". In most cases, choose Filled for the original visual intent; use Solid for a high-contrast solid background. Preset, status, and custom colors are combined with Variant to determine background, foreground, and border.

Checkable scenarios use CheckableTag

Regular Tag continues to own display, color, and close behavior. Use CheckableTag for binary selection and CheckableTagGroup for collection selection:

<atom:CheckableTag
    Content="Preview features"
    IsChecked="{Binding IsPreviewEnabled}" />

Single selection:

<atom:CheckableTagGroup
    Options="{Binding Categories}"
    CheckedItem="{Binding SelectedCategory}" />

Multiple selection:

<atom:CheckableTagGroup
    Options="{Binding Categories}"
    IsMultiple="True"
    CheckedItems="{Binding SelectedCategories}" />

CheckableTag does not expose regular Tag APIs such as TagColor, Variant, IsClosable, or close events.

Separator Customizable Size Migration

Separator.SizeType changed from SizeType to CustomizableSizeType, and Separator now implements ICustomizableSizeTypeAware.

The XAML names Small, Middle, and Large are unchanged in common markup:

<atom:Separator SizeType="Small" />

C# code that reads or writes the strongly typed property must be updated:

// 6.1.2
separator.SizeType = SizeType.Small;

// 6.1.3
separator.SizeType = CustomizableSizeType.Small;

Custom does not apply AtomUI preset block margins. Spacing should be provided by the control instance or its owning style:

<atom:Separator
    SizeType="Custom"
    Margin="0,4" />

Custom methods, interfaces, or ViewModel properties that declared SizeType should migrate to CustomizableSizeType. Do not rely on implicit enum conversions.

Upgrade Checklist

Before upgrading, search for the old contracts in this order:

WithAlgorithms("
AddControlToken
AddControlThemesProvider
LanguageCode
LanguageVariant
LanguageProvider
AddLanguageProviders
Accepts
IsOpenFileDialogOnClick
FilesDropped
UploadFilesDroppedEventArgs
TimelineMode.Left
TimelineMode.Right
IndicatorLeftModeMargin
IndicatorRightModeMargin
IsBordered
Separator.SizeType

Typical AtomUI applications without custom Theme, Localization, or Upload pipelines mainly need to check Timeline, Tag, and Separator usage in XAML or C#. If the only change is the Avalonia 12.1.1 dependency patch and the AtomUI public contract changes listed here are not included, no migration from this page is required.