8.3 KiB
AtomUI 6.0.8 API Change Examples
This document supplements the main 6.0.8 release notes with the most important API changes and migration examples from 6.0.7.
For the authoritative release entries, see the repository root CHANGELOG.md and CHANGELOG.zh-CN.md.
Chinese version: 6.0.8 API 变更示例.
ImagePreviewer Image Source Migration
6.0.8 unifies ImagePreviewer image sources around IImagePreviewSource:
SourceUri->SourceSourceUris->SourcesFallbackSourceUri->FallbackSource- Use
UriImagePreviewSourcefor URI, local file, and Avalonia resource images. - Use
StreamImagePreviewSourcefor database, authenticated network, encrypted file, memory, and other lazy stream sources.
6.0.7
<atom:ImagePreviewer
SourceUri="https://example.com/photo.jpg"
FallbackSourceUri="avares://Demo/Assets/fallback.png" />
6.0.8
using AtomUI.Desktop.Controls;
public IImagePreviewSource PreviewSource { get; } =
new UriImagePreviewSource("https://example.com/photo.jpg");
public IImagePreviewSource PreviewFallbackSource { get; } =
new UriImagePreviewSource("avares://Demo/Assets/fallback.png");
<atom:ImagePreviewer
Source="{Binding PreviewSource}"
FallbackSource="{Binding PreviewFallbackSource}" />
Multiple Images, Cover, and Preloading
CoverIndex only controls which image is shown as the closed-state cover.
It does not change CurrentIndex.
public IList<IImagePreviewSource> PreviewImages { get; } =
[
new UriImagePreviewSource("https://example.com/photo-1.jpg"),
new UriImagePreviewSource("https://example.com/photo-2.jpg"),
new UriImagePreviewSource("https://example.com/photo-3.jpg")
];
public int CurrentPreviewIndex { get; set; }
<atom:ImageGroupPreviewer
Sources="{Binding PreviewImages}"
CoverIndex="1"
CurrentIndex="{Binding CurrentPreviewIndex}"
MaxConcurrentLoads="4"
PreloadCount="1" />
Lazy Stream Sources
OpenReadAsync should return a new readable stream each time it is called.
ImagePreviewer owns and disposes the returned stream.
public IImagePreviewSource SecurePreviewSource { get; } =
new StreamImagePreviewSource(
openReadAsync: cancellationToken =>
{
Stream stream = File.OpenRead("/secure/photos/invoice.png");
return new ValueTask<Stream>(stream);
},
displayName: "invoice.png",
contentType: "image/png",
identity: "/secure/photos/invoice.png");
Upload Composable Trigger Migration
In 6.0.8, the root Upload control owns file state, the queue, Form values, and lifecycle.
File selection, directory selection, and drop input are handled by composable controls.
6.0.7
<atom:Upload
IsUploadDirectoryEnabled="True"
IsShowUploadTrigger="True"
DefaultTaskList="{Binding DefaultTaskList}"
UploadTransport="{Binding UploadTransport}" />
6.0.8
using AtomUI.Desktop.Controls;
using System.Collections.ObjectModel;
public ObservableCollection<UploadFileItem> Attachments { get; } = [];
public IFileUploadTransport UploadTransport { get; } = new MyUploadTransport();
<atom:Upload
Files="{Binding Attachments}"
UploadTransport="{Binding UploadTransport}"
AutoUpload="True"
ListMaxHeight="180"
ListScrollBarVisibility="Auto"
SuccessAutoRemoveDelay="0:0:3">
<atom:Space>
<atom:UploadTrigger SourceKind="Files">
<atom:Button Content="Select files" />
</atom:UploadTrigger>
<atom:UploadTrigger SourceKind="Directories">
<atom:Button Content="Select directory" />
</atom:UploadTrigger>
</atom:Space>
</atom:Upload>
Drag-and-Drop Upload
<atom:Upload
Files="{Binding Attachments}"
UploadTransport="{Binding UploadTransport}">
<atom:UploadDropZone>
<TextBlock Text="Drop files here" />
</atom:UploadDropZone>
</atom:Upload>
Form Value Projection
FileValueMode controls the value Upload writes into Form:
<atom:Upload
Files="{Binding Attachments}"
FileValueMode="Results"
UploadTransport="{Binding UploadTransport}" />
New OtpLineEdit Control
OtpLineEdit uses one Text value for the complete verification code.
Cells, separators, and masking only affect visuals.
<atom:OtpLineEdit
Text="{Binding Code}"
Length="6"
InputMode="Numeric"
Separator="-"
SeparatorInterval="3"
StyleVariant="Outlined" />
<atom:OtpLineEdit
Text="{Binding RecoveryCode}"
Length="8"
InputMode="AlphaNumeric"
IsMasked="True"
PlaceholderText="•" />
public string? Code { get; set; }
Form and DataValidationErrors
In 6.0.8, errors produced by Form validators are written to Avalonia DataValidationErrors.
If a ViewModel validator, binding validator, or application validation layer already provides a native validation error, AtomUI controls display that native error with highest priority.
The default trigger is OnChanged.
Configure OnBlur explicitly when validation should run after focus leaves the field:
<atom:Form ValidateTrigger="OnBlur">
<atom:FormItem Name="UserName" IsRequired="True">
<atom:LineEdit Text="{Binding UserName}" />
</atom:FormItem>
</atom:Form>
Default Two-Way Bindings
Several selection and value properties now use BindingMode.TwoWay by default.
Common scenarios no longer need explicit Mode=TwoWay:
<atom:Select
OptionsSource="{Binding CityOptions}"
SelectedOption="{Binding SelectedCity}" />
<atom:TreeSelect
ItemsSource="{Binding TreeNodes}"
SelectedItems="{Binding SelectedTreeNodes}" />
<atom:DatePicker SelectedDateTime="{Binding SelectedDate}" />
<atom:TimePicker SelectedTime="{Binding SelectedTime}" />
<atom:Rate Value="{Binding Rating}" />
<atom:Dialog IsOpen="{Binding IsSettingsOpen}" />
If application logic needs a read-only projection, set Mode=OneWay explicitly on the binding.
DataGrid Filter Model
Column filters now live directly on column APIs, and both the filter item source and selected values are bindable:
<atom:DataGridTextColumn
Header="Name"
Binding="{Binding Name}"
Filters="{Binding NameFilters}"
SelectedFilterValues="{Binding SelectedNames}"
FilterTextMemberPath="Text"
FilterValueMemberPath="Value"
FilterPresenterMode="Menu"
FilterSelectionMode="Multiple"
FilterApplyMode="SelectionChanged" />
Tree filters use FilterChildrenMemberPath:
<atom:DataGridTextColumn
Header="Department"
Binding="{Binding Department}"
Filters="{Binding DepartmentFilters}"
SelectedFilterValues="{Binding SelectedDepartments}"
FilterTextMemberPath="Name"
FilterValueMemberPath="Id"
FilterChildrenMemberPath="Children"
FilterPresenterMode="Tree" />
Select, ComboBox, and Cascader Overflow Tips
Enable overflow tooltips when selected content cannot be fully displayed:
<atom:Select
IsShowOverflowTip="True"
OverflowTipDelay="800"
OverflowTipPlacement="TopEdgeAlignedLeft"
OptionsSource="{Binding Options}"
SelectedOptions="{Binding SelectedOptions}" />
<atom:ComboBox
IsShowOverflowTip="True"
OverflowTipDelay="800"
OverflowTipPlacement="TopEdgeAlignedLeft"
ItemsSource="{Binding Items}" />
TabControl and TabStrip Reordering
<atom:TabControl
IsTabReorderEnabled="True"
TabActivationTrigger="PointerReleased"
TabReordering="HandleTabReordering"
TabReordered="HandleTabReordered">
<atom:TabItem Header="Tab 1">Content 1</atom:TabItem>
<atom:TabItem Header="Tab 2">Content 2</atom:TabItem>
<atom:TabItem Header="Tab 3">Content 3</atom:TabItem>
</atom:TabControl>
TabActivationTrigger="PointerReleased" is the default and fits tab reordering scenarios.
Use PointerPressed when tabs should activate as soon as the pointer is pressed.
Dialog Async Close Validation
await Dialog.ShowDialogAsync(
new TextBlock { Text = "Close without saving?" },
options: new DialogOptions
{
Title = "Unsaved changes",
BeforeCloseAsync = async context =>
{
if (context.Reason == DialogCloseReason.Rejected)
{
return true;
}
return await ConfirmSaveAsync();
}
});