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.