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

11 KiB

AtomUI 6.1.0 API Change Examples

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

Chinese version: 6.1.0 API 变更示例.

Dialog and MessageBox Async Session Migration

6.1.0 unifies Dialog and MessageBox static display APIs, close requests, and host lifecycle around an async session model:

  • Synchronous static APIs have been removed: ShowDialog, ShowDialogModal, and ShowMessageBox.
  • Async static APIs with a closed callback have been removed.
  • External host extension points have been removed: IDialogHost and IDialogHostProvider.
  • Result wrapper interfaces have been removed: IDialogActionResult and IMessageBoxActionResult.
  • Static APIs now return Task<object?>; read the close result from the awaited result directly.
  • Close validation now uses BeforeCloseAsync consistently.

Synchronous Static Dialog Calls

6.0.8

object? result = Dialog.ShowDialog<SettingsDialogView, SettingsDialogViewModel>(
    viewModel,
    new DialogOptions
    {
        Title           = "Settings",
        StandardButtons = DialogStandardButton.Ok | DialogStandardButton.Cancel
    },
    topLevel);

if (result is DialogCode.Accepted)
{
    SaveSettings();
}

6.1.0

object? result = await Dialog.ShowDialogAsync<SettingsDialogView, SettingsDialogViewModel>(
    viewModel,
    new DialogOptions
    {
        Title           = "Settings",
        StandardButtons = DialogStandardButton.Ok | DialogStandardButton.Cancel
    },
    topLevel);

if (result is DialogCode.Accepted)
{
    SaveSettings();
}

Callback-Style Dialog Close Results

6.0.8

await Dialog.ShowDialogAsync(
    new SettingsDialogView(),
    viewModel,
    new DialogOptions
    {
        Title           = "Settings",
        StandardButtons = DialogStandardButton.Ok | DialogStandardButton.Cancel
    },
    closed: actionResult =>
    {
        if (actionResult.Result is DialogCode.Accepted)
        {
            SaveSettings();
        }
    },
    topLevel);

6.1.0

object? result = await Dialog.ShowDialogAsync(
    new SettingsDialogView(),
    viewModel,
    new DialogOptions
    {
        Title           = "Settings",
        StandardButtons = DialogStandardButton.Ok | DialogStandardButton.Cancel
    },
    topLevel);

if (result is DialogCode.Accepted)
{
    SaveSettings();
}

Opening Dialog Instances

When creating a Dialog or MessageBox instance directly, migrate synchronous Open() calls to async OpenAsync(). Read the close result from the instance Result property.

6.0.8

var dialog = new Dialog
{
    Title           = "Settings",
    Content         = new SettingsDialogView(),
    DataContext     = viewModel,
    StandardButtons = DialogStandardButton.Ok | DialogStandardButton.Cancel
};

object? result = dialog.Open();

if (result is DialogCode.Accepted)
{
    SaveSettings();
}

6.1.0

var dialog = new Dialog
{
    Title           = "Settings",
    Content         = new SettingsDialogView(),
    DataContext     = viewModel,
    StandardButtons = DialogStandardButton.Ok | DialogStandardButton.Cancel
};

await dialog.OpenAsync();
object? result = dialog.Result;

if (result is DialogCode.Accepted)
{
    SaveSettings();
}

MessageBox Static API Names and Results

6.0.8

await MessageBox.ShowMessageAsync(
    new DeleteConfirmView(),
    dataContext,
    new MessageBoxOptions
    {
        Title = "Delete item",
        Style = MessageBoxStyle.Confirm
    },
    closed: actionResult =>
    {
        if (actionResult.Result is DialogCode.Accepted)
        {
            DeleteItem();
        }
    },
    topLevel);

6.1.0

object? result = await MessageBox.ShowMessageBoxAsync(
    new DeleteConfirmView(),
    dataContext,
    new MessageBoxOptions
    {
        Title = "Delete item",
        Style = MessageBoxStyle.Confirm
    },
    topLevel);

if (result is DialogCode.Accepted)
{
    DeleteItem();
}

Modal MessageBox also uses the full method name:

object? result = await MessageBox.ShowMessageBoxModalAsync(
    new DeleteConfirmView(),
    dataContext,
    new MessageBoxOptions
    {
        Title = "Delete item",
        Style = MessageBoxStyle.Warning
    },
    topLevel);

Close Validation

BeforeCloseAsync is now the unified validation entry point for Dialog and MessageBox close requests. Return false to reject the close request; return true to allow it.

object? result = await Dialog.ShowDialogAsync(
    new EditProfileView(),
    viewModel,
    new DialogOptions
    {
        Title           = "Edit profile",
        StandardButtons = DialogStandardButton.Ok | DialogStandardButton.Cancel,
        BeforeCloseAsync = async context =>
        {
            if (context.DialogCode is DialogCode.Accepted)
            {
                return await viewModel.ValidateAndSaveAsync(context.CancellationToken);
            }

            return true;
        }
    },
    topLevel);

Custom Dialog Hosts

If a project implemented IDialogHost or IDialogHostProvider to take over overlay hosts, 6.1.0 no longer supports that extension path. Prefer the built-in host selection and placement configuration:

object? result = await Dialog.ShowDialogAsync(
    new DetailsDialogView(),
    viewModel,
    new DialogOptions
    {
        DialogHostType  = DialogHostType.Overlay,
        PlacementTarget = ownerPanel,
        HostWidth       = 520,
        HostMinHeight   = 240
    },
    topLevel);

Choose DialogHostType.Window explicitly when a separate window host is required:

object? result = await Dialog.ShowDialogModalAsync(
    new ReportDialogView(),
    viewModel,
    new DialogOptions
    {
        DialogHostType = DialogHostType.Window,
        Title          = "Report"
    },
    topLevel);

Steps Controlled State Migration

6.1.0 changes Steps from SelectingItemsControl to ItemsControl. Public state is now expressed through Current, Initial, Status, Percent, Type, and TitlePlacement.

API Reference

6.0.8 API 6.1.0 API Notes
CurrentStep Current Current step number
InitialStep Initial Number offset for the first step
CurrentStepStatus Status Current step status
StepsItemStatus StepsStatus Status enum rename
StepsStyle + StepsItemIndicatorType StepsType Style and indicator type merged
LabelPlacement TitlePlacement Title layout placement
ProgressValue + IsShowItemProgress Percent Nullable progress value; null hides progress
SelectedIndex / SelectedItem Current + CurrentChangeRequested Selection state is no longer used
CurrentContent / CurrentContentTemplate Project from application ViewModel Steps no longer owns a current-item content outlet
StepsItem.Description / DescriptionTemplate StepsItem.Content / ContentTemplate Step details now use the standard Content contract

Basic XAML Property Migration

6.0.8

<atom:Steps
    CurrentStep="{Binding CurrentStep}"
    InitialStep="1"
    CurrentStepStatus="Process"
    Style="Default"
    ItemIndicatorType="Dot"
    LabelPlacement="Vertical"
    IsShowItemProgress="True"
    ProgressValue="{Binding ProgressValue}" />

6.1.0

<atom:Steps
    Current="{Binding CurrentStep}"
    Initial="1"
    Status="Process"
    Type="Dot"
    TitlePlacement="Vertical"
    Percent="{Binding ProgressValue}" />

If old markup used Style="Navigation" or Style="Inline", migrate directly to Type="Navigation" or Type="Inline". If old markup used the default style with ItemIndicatorType="Default", omit Type or set Type="Default".

Clickable Steps

CurrentChangeRequested means “the user requested a step change.” The control does not mutate Current directly on click; application code confirms that the transition is allowed, then updates the bound Current.

6.0.8

<atom:Steps
    CurrentStep="{Binding CurrentStep}"
    IsItemClickable="True" />

6.1.0

<atom:Steps
    Current="{Binding CurrentStep}"
    IsItemClickable="True"
    CurrentChangeRequested="HandleCurrentChangeRequested" />
private void HandleCurrentChangeRequested(
    object? sender,
    StepsCurrentChangeRequestedEventArgs e)
{
    if (ViewModel.CanMoveTo(e.Current))
    {
        ViewModel.CurrentStep = e.Current;
    }
}

Step Item Description Content

6.0.8

<atom:Steps>
    <atom:StepsItem
        Header="Login"
        Description="Sign in with your account" />
    <atom:StepsItem
        Header="Verify"
        Description="Enter the verification code" />
</atom:Steps>

6.1.0

<atom:Steps>
    <atom:StepsItem Header="Login">
        Sign in with your account
    </atom:StepsItem>
    <atom:StepsItem Header="Verify">
        Enter the verification code
    </atom:StepsItem>
</atom:Steps>

Use ContentTemplate for richer description content:

<atom:StepsItem Header="Verify" Content="{Binding VerifyStep}">
    <atom:StepsItem.ContentTemplate>
        <DataTemplate>
            <atom:Space Orientation="Vertical" Spacing="4">
                <TextBlock Text="{Binding Summary}" />
                <TextBlock Text="{Binding HelpText}" />
            </atom:Space>
        </DataTemplate>
    </atom:StepsItem.ContentTemplate>
</atom:StepsItem>

Current Step Content Projection

CurrentContent and CurrentContentTemplate have been removed. When a page needs to show the current step content outside Steps, project it from the ViewModel based on Current.

6.0.8

<atom:Steps
    x:Name="WizardSteps"
    CurrentStep="{Binding CurrentStep}"
    ContentTemplate="{StaticResource WizardStepTemplate}" />

<ContentControl
    Content="{Binding #WizardSteps.CurrentContent}"
    ContentTemplate="{Binding #WizardSteps.CurrentContentTemplate}" />

6.1.0

<atom:Steps
    Current="{Binding CurrentStep}"
    CurrentChangeRequested="HandleCurrentChangeRequested" />

<ContentControl
    Content="{Binding CurrentStepContent}"
    ContentTemplate="{StaticResource WizardStepTemplate}" />
public object? CurrentStepContent => Steps.FirstOrDefault(step => step.Number == CurrentStep);

private void HandleCurrentChangeRequested(
    object? sender,
    StepsCurrentChangeRequestedEventArgs e)
{
    CurrentStep = e.Current;
    RaisePropertyChanged(nameof(CurrentStepContent));
}

Explicit Step Status

StepsItem.Status is now nullable. When it is not set, Steps derives the automatic status from Current, Initial, and the root Status. Set it only when overriding a specific step:

<atom:Steps Current="{Binding CurrentStep}" Status="Process">
    <atom:StepsItem Header="Create" />
    <atom:StepsItem Header="Review" Status="Error" />
    <atom:StepsItem Header="Publish" />
</atom:Steps>

This pins only Review to Error; the other steps continue to use automatic status.