fluentui-blazor

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Fluent UI Blazor — Consumer Usage Guide

Fluent UI Blazor — 使用者使用指南

This skill teaches how to correctly use the Microsoft.FluentUI.AspNetCore.Components (version 4) NuGet package in Blazor applications.
本指南介绍如何在Blazor应用中正确使用Microsoft.FluentUI.AspNetCore.Components(4.x版本)NuGet包。

Critical Rules

核心规则

1. No manual
<script>
or
<link>
tags needed

1. 无需手动添加
<script>
<link>
标签

The library auto-loads all CSS and JS via Blazor's static web assets and JS initializers. Never tell users to add
<script>
or
<link>
tags for the core library.
该库通过Blazor的静态Web资源和JS初始化程序自动加载所有CSS和JS。切勿告知用户为核心库添加
<script>
<link>
标签。

2. Providers are mandatory for service-based components

2. 服务型组件必须添加提供程序

These provider components MUST be added to the root layout (e.g.
MainLayout.razor
) for their corresponding services to work. Without them, service calls fail silently (no error, no UI).
razor
<FluentToastProvider />
<FluentDialogProvider />
<FluentMessageBarProvider />
<FluentTooltipProvider />
<FluentKeyCodeProvider />
这些提供程序组件必须添加到根布局(例如
MainLayout.razor
)中,对应的服务才能正常工作。如果不添加,服务调用会静默失败(无错误提示,无UI反馈)。
razor
<FluentToastProvider />
<FluentDialogProvider />
<FluentMessageBarProvider />
<FluentTooltipProvider />
<FluentKeyCodeProvider />

3. Service registration in Program.cs

3. 在Program.cs中注册服务

csharp
builder.Services.AddFluentUIComponents();

// Or with configuration:
builder.Services.AddFluentUIComponents(options =>
{
    options.UseTooltipServiceProvider = true;  // default: true
    options.ServiceLifetime = ServiceLifetime.Scoped; // default
});
ServiceLifetime rules:
  • ServiceLifetime.Scoped
    — for Blazor Server / Interactive (default)
  • ServiceLifetime.Singleton
    — for Blazor WebAssembly standalone
  • ServiceLifetime.Transient
    throws
    NotSupportedException
csharp
builder.Services.AddFluentUIComponents();

// 或带配置的注册方式:
builder.Services.AddFluentUIComponents(options =>
{
    options.UseTooltipServiceProvider = true;  // 默认值:true
    options.ServiceLifetime = ServiceLifetime.Scoped; // 默认值
});
服务生命周期规则:
  • ServiceLifetime.Scoped
    — 适用于Blazor Server / 交互式模式(默认)
  • ServiceLifetime.Singleton
    — 适用于Blazor WebAssembly独立模式
  • ServiceLifetime.Transient
    会抛出
    NotSupportedException
    异常

4. Icons require a separate NuGet package

4. 图标需要单独的NuGet包

dotnet add package Microsoft.FluentUI.AspNetCore.Components.Icons
Usage with a
@using
alias:
razor
@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons

<FluentIcon Value="@(Icons.Regular.Size24.Save)" />
<FluentIcon Value="@(Icons.Filled.Size20.Delete)" Color="@Color.Error" />
Pattern:
Icons.[Variant].[Size].[Name]
  • Variants:
    Regular
    ,
    Filled
  • Sizes:
    Size12
    ,
    Size16
    ,
    Size20
    ,
    Size24
    ,
    Size28
    ,
    Size32
    ,
    Size48
Custom image:
Icon.FromImageUrl("/path/to/image.png")
Never use string-based icon names — icons are strongly-typed classes.
dotnet add package Microsoft.FluentUI.AspNetCore.Components.Icons
通过
@using
别名使用:
razor
@using Icons = Microsoft.FluentUI.AspNetCore.Components.Icons

<FluentIcon Value="@(Icons.Regular.Size24.Save)" />
<FluentIcon Value="@(Icons.Filled.Size20.Delete)" Color="@Color.Error" />
使用模式:
Icons.[Variant].[Size].[Name]
  • 变体:
    Regular
    Filled
  • 尺寸:
    Size12
    Size16
    Size20
    Size24
    Size28
    Size32
    Size48
自定义图片:
Icon.FromImageUrl("/path/to/image.png")
切勿使用字符串形式的图标名称 — 图标是强类型类。

5. List component binding model

5. 列表组件绑定模型

FluentSelect<TOption>
,
FluentCombobox<TOption>
,
FluentListbox<TOption>
, and
FluentAutocomplete<TOption>
do NOT work like
<InputSelect>
. They use:
  • Items
    — the data source (
    IEnumerable<TOption>
    )
  • OptionText
    Func<TOption, string?>
    to extract display text
  • OptionValue
    Func<TOption, string?>
    to extract the value string
  • SelectedOption
    /
    SelectedOptionChanged
    — for single selection binding
  • SelectedOptions
    /
    SelectedOptionsChanged
    — for multi-selection binding
razor
<FluentSelect Items="@countries"
              OptionText="@(c => c.Name)"
              OptionValue="@(c => c.Code)"
              @bind-SelectedOption="@selectedCountry"
              Label="Country" />
NOT like this (wrong pattern):
razor
@* WRONG — do not use InputSelect pattern *@
<FluentSelect @bind-Value="@selectedValue">
    <option value="1">One</option>
</FluentSelect>
FluentSelect<TOption>
FluentCombobox<TOption>
FluentListbox<TOption>
FluentAutocomplete<TOption>
的工作方式与
<InputSelect>
不同。它们使用以下参数:
  • Items
    — 数据源(
    IEnumerable<TOption>
  • OptionText
    — 提取显示文本的
    Func<TOption, string?>
    委托
  • OptionValue
    — 提取值字符串的
    Func<TOption, string?>
    委托
  • SelectedOption
    /
    SelectedOptionChanged
    — 用于单选绑定
  • SelectedOptions
    /
    SelectedOptionsChanged
    — 用于多选绑定
razor
<FluentSelect Items="@countries"
              OptionText="@(c => c.Name)"
              OptionValue="@(c => c.Code)"
              @bind-SelectedOption="@selectedCountry"
              Label="Country" />
请勿使用以下错误模式:
razor
@* 错误 — 不要使用InputSelect的模式 *@
<FluentSelect @bind-Value="@selectedValue">
    <option value="1">One</option>
</FluentSelect>

6. FluentAutocomplete specifics

6. FluentAutocomplete的特殊说明

  • Use
    ValueText
    (NOT
    Value
    — it's obsolete) for the search input text
  • OnOptionsSearch
    is the required callback to filter options
  • Default is
    Multiple="true"
razor
<FluentAutocomplete TOption="Person"
                    OnOptionsSearch="@OnSearch"
                    OptionText="@(p => p.FullName)"
                    @bind-SelectedOptions="@selectedPeople"
                    Label="Search people" />

@code {
    private void OnSearch(OptionsSearchEventArgs<Person> args)
    {
        args.Items = allPeople.Where(p =>
            p.FullName.Contains(args.Text, StringComparison.OrdinalIgnoreCase));
    }
}
  • 使用
    ValueText
    (而非已废弃的
    Value
    )作为搜索输入文本
  • OnOptionsSearch
    是必填的回调函数,用于过滤选项
  • 默认
    Multiple="true"
razor
<FluentAutocomplete TOption="Person"
                    OnOptionsSearch="@OnSearch"
                    OptionText="@(p => p.FullName)"
                    @bind-SelectedOptions="@selectedPeople"
                    Label="Search people" />

@code {
    private void OnSearch(OptionsSearchEventArgs<Person> args)
    {
        args.Items = allPeople.Where(p =>
            p.FullName.Contains(args.Text, StringComparison.OrdinalIgnoreCase));
    }
}

7. Dialog service pattern

7. 对话框服务模式

Do NOT toggle visibility of
<FluentDialog>
tags.
The service pattern is:
  1. Create a content component implementing
    IDialogContentComponent<TData>
    :
csharp
public partial class EditPersonDialog : IDialogContentComponent<Person>
{
    [Parameter] public Person Content { get; set; } = default!;

    [CascadingParameter] public FluentDialog Dialog { get; set; } = default!;

    private async Task SaveAsync()
    {
        await Dialog.CloseAsync(Content);
    }

    private async Task CancelAsync()
    {
        await Dialog.CancelAsync();
    }
}
  1. Show the dialog via
    IDialogService
    :
csharp
[Inject] private IDialogService DialogService { get; set; } = default!;

private async Task ShowEditDialog()
{
    var dialog = await DialogService.ShowDialogAsync<EditPersonDialog, Person>(
        person,
        new DialogParameters
        {
            Title = "Edit Person",
            PrimaryAction = "Save",
            SecondaryAction = "Cancel",
            Width = "500px",
            PreventDismissOnOverlayClick = true,
        });

    var result = await dialog.Result;
    if (!result.Cancelled)
    {
        var updatedPerson = result.Data as Person;
    }
}
For convenience dialogs:
csharp
await DialogService.ShowConfirmationAsync("Are you sure?", "Yes", "No");
await DialogService.ShowSuccessAsync("Done!");
await DialogService.ShowErrorAsync("Something went wrong.");
请勿切换
<FluentDialog>
标签的可见性
。正确的服务模式如下:
  1. 创建实现
    IDialogContentComponent<TData>
    的内容组件:
csharp
public partial class EditPersonDialog : IDialogContentComponent<Person>
{
    [Parameter] public Person Content { get; set; } = default!;

    [CascadingParameter] public FluentDialog Dialog { get; set; } = default!;

    private async Task SaveAsync()
    {
        await Dialog.CloseAsync(Content);
    }

    private async Task CancelAsync()
    {
        await Dialog.CancelAsync();
    }
}
  1. 通过
    IDialogService
    显示对话框:
csharp
[Inject] private IDialogService DialogService { get; set; } = default!;

private async Task ShowEditDialog()
{
    var dialog = await DialogService.ShowDialogAsync<EditPersonDialog, Person>(
        person,
        new DialogParameters
        {
            Title = "Edit Person",
            PrimaryAction = "Save",
            SecondaryAction = "Cancel",
            Width = "500px",
            PreventDismissOnOverlayClick = true,
        });

    var result = await dialog.Result;
    if (!result.Cancelled)
    {
        var updatedPerson = result.Data as Person;
    }
}
便捷对话框使用方式:
csharp
await DialogService.ShowConfirmationAsync("Are you sure?", "Yes", "No");
await DialogService.ShowSuccessAsync("Done!");
await DialogService.ShowErrorAsync("Something went wrong.");

8. Toast notifications

8. 通知提示框(Toast)

csharp
[Inject] private IToastService ToastService { get; set; } = default!;

ToastService.ShowSuccess("Item saved successfully");
ToastService.ShowError("Failed to save");
ToastService.ShowWarning("Check your input");
ToastService.ShowInfo("New update available");
FluentToastProvider
parameters:
Position
(default
TopRight
),
Timeout
(default 7000ms),
MaxToastCount
(default 4).
csharp
[Inject] private IToastService ToastService { get; set; } = default!;

ToastService.ShowSuccess("Item saved successfully");
ToastService.ShowError("Failed to save");
ToastService.ShowWarning("Check your input");
ToastService.ShowInfo("New update available");
FluentToastProvider
的参数:
Position
(默认
TopRight
)、
Timeout
(默认7000毫秒)、
MaxToastCount
(默认4)。

9. Design tokens and themes work only after render

9. 设计令牌和主题仅在渲染后生效

Design tokens rely on JS interop. Never set them in
OnInitialized
— use
OnAfterRenderAsync
.
razor
<FluentDesignTheme Mode="DesignThemeModes.System"
                   OfficeColor="OfficeColor.Teams"
                   StorageName="mytheme" />
设计令牌依赖JS互操作。切勿在
OnInitialized
中设置
— 请使用
OnAfterRenderAsync
razor
<FluentDesignTheme Mode="DesignThemeModes.System"
                   OfficeColor="OfficeColor.Teams"
                   StorageName="mytheme" />

10. FluentEditForm vs EditForm

10. FluentEditForm与EditForm的区别

FluentEditForm
is only needed inside
FluentWizard
steps (per-step validation). For regular forms, use standard
EditForm
with Fluent form components:
razor
<EditForm Model="@model" OnValidSubmit="HandleSubmit">
    <DataAnnotationsValidator />
    <FluentTextField @bind-Value="@model.Name" Label="Name" Required />
    <FluentSelect Items="@options"
                  OptionText="@(o => o.Label)"
                  @bind-SelectedOption="@model.Category"
                  Label="Category" />
    <FluentValidationSummary />
    <FluentButton Type="ButtonType.Submit" Appearance="Appearance.Accent">Save</FluentButton>
</EditForm>
Use
FluentValidationMessage
and
FluentValidationSummary
instead of standard Blazor validation components for Fluent styling.
只有在
FluentWizard
步骤中(分步验证)才需要使用
FluentEditForm
。对于常规表单,请使用标准
EditForm
搭配Fluent表单组件:
razor
<EditForm Model="@model" OnValidSubmit="HandleSubmit">
    <DataAnnotationsValidator />
    <FluentTextField @bind-Value="@model.Name" Label="Name" Required />
    <FluentSelect Items="@options"
                  OptionText="@(o => o.Label)"
                  @bind-SelectedOption="@model.Category"
                  Label="Category" />
    <FluentValidationSummary />
    <FluentButton Type="ButtonType.Submit" Appearance="Appearance.Accent">Save</FluentButton>
</EditForm>
为了适配Fluent样式,请使用
FluentValidationMessage
FluentValidationSummary
替代标准Blazor验证组件。

Reference files

参考文档

For detailed guidance on specific topics, see:
  • Setup and configuration
  • Layout and navigation
  • Data grid
  • Theming
如需特定主题的详细指导,请查看:
  • 安装与配置
  • 布局与导航
  • 数据网格
  • 主题设置