Я пытаюсь заставить FluentDialogProvider работать, чтобы он отображал панель. Это ошибка, которую я получаю:
warn: Microsoft.AspNetCore.Components.Server.Circuits.RemoteRenderer[100]
Unhandled exception rendering component: <FluentDialogProvider /> needs to be added to the main layout of your application/site. (Parameter 'OnShowAsync') System.ArgumentNullException: <FluentDialogProvider /> needs to be added to the main layout of your application/site. (Parameter 'OnShowAsync')
at Microsoft.FluentUI.AspNetCore.Components.DialogService.ShowDialogAsync[TData](Type dialogComponent, TData data, DialogParameters parameters) in /_/src/Core/Components/Dialog/Services/DialogService-Dialog.cs:line 17
at Microsoft.FluentUI.AspNetCore.Components.DialogService.ShowPanelAsync[TDialog](Object data, DialogParameters parameters) in /_/src/Core/Components/Dialog/Services/DialogService-Dialog.cs:line 56
at S2IX.NodeManager.UI.Web.Shared.Nodes.NodeSnapshots.OpenPanelRightAsync(Guid server) in E:\repos\nodemanager\NodeManager\S2IX.NodeManager.UI.Web\Shared\Nodes\NodeSnapshots.razor:line 108
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
fail: Microsoft.AspNetCore.Components.Server.Circuits.CircuitHost[111]
Unhandled exception in circuit 'BvKsO6dDjcGDj2ubE1pbKa4oPkFQ1ZRukm-frbIFvGI'.
System.ArgumentNullException: <FluentDialogProvider /> needs to be added to the main layout of your application/site. (Parameter 'OnShowAsync')
at Microsoft.FluentUI.AspNetCore.Components.DialogService.ShowDialogAsync[TData](Type dialogComponent, TData data, DialogParameters parameters) in /_/src/Core/Components/Dialog/Services/DialogService-Dialog.cs:line 17
at Microsoft.FluentUI.AspNetCore.Components.DialogService.ShowPanelAsync[TDialog](Object data, DialogParameters parameters) in /_/src/Core/Components/Dialog/Services/DialogService-Dialog.cs:line 56
at S2IX.NodeManager.UI.Web.Shared.Nodes.NodeSnapshots.OpenPanelRightAsync(Guid server) in E:\repos\nodemanager\NodeManager\S2IX.NodeManager.UI.Web\Shared\Nodes\NodeSnapshots.razor:line 108
at Microsoft.AspNetCore.Components.ComponentBase.CallStateHasChangedOnAsyncCompletion(Task task)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle, ComponentState owningComponentState)
Я зарегистрировал компоненты в своем Startup.cs, а также добавил DialogueService в соответствии с областью действия. Он также находится в моем MainLayout.cs в этом разделе. Не совсем понимаю, что здесь происходит, поскольку мне кажется, что я правильно следовал документации.
Программа.cs:
builder.Services.AddScoped<DialogService>();
builder.Services.AddFluentUIComponents();
Mainlayout.cs:
@inherits LayoutComponentBase
@using S2IX.NodeManager.UI.Web.Shared.CommandBars
@using S2IX.NodeManager.Models
<FluentLayout Style = "display: flex; height: auto;">
<FluentHeader style = "background-color:#29ABE2; height: 75px;">
<img src = "/Images/s2ixbrand.png" alt = "S2IX" />
</FluentHeader>
<FluentBodyContent>
<FluentStack Orientation = "Orientation.Horizontal" Style = "justify-content: space-between; ">
@if (collapseMenu)
{
<FluentStack Orientation = "Orientation.Vertical" Style = "width: auto; height: 100vh;">
<NavMenu />
</FluentStack>
}
<main style = "width:auto;">
<div class = "content">
<article id = "article">
<AppCommandBar />
@Body
</article>
</div>
<FluentToastProvider MaxToastCount = "5" Position = "ToastPosition.BottomRight" RemoveToastsOnNavigation = "true" />
<FluentDialogProvider />
<FluentTooltipProvider />
<FluentMessageBarProvider />
</main>
</FluentStack>
</FluentBodyContent>
</FluentLayout>
@code {
bool collapseMenu = true;
void ToggleMenu()
{
collapseMenu = !collapseMenu;
StateHasChanged();
}
}
NodeSnapshots.cs:
@inject ApplicationStateService stateService
@inject NavigationManager navMan
@inject IDialogService DialogService
@rendermode RenderMode.InteractiveServer
@if (!nodesFound)
{
@if (!showDialog)
{
<FluentProgressRing>Loading Nodes...</FluentProgressRing>
}
else
{
<p>No Nodes found</p>
}
}
else
{
<FluentDataGrid Items = "@FilteredItems" ResizableColumns = "false" Pagination = "@pagination" Style = "overflow:auto;">
<PropertyColumn Title = "Name" Property = "@(n => n.Name)" Sortable = "true">
<ColumnOptions>
<div class = "search-box">
<FluentSearch type = "search" Autofocus = "true" @bind-Value=nodeFilter @oninput = "HandleNameFilter" @bind-Value:after = "HandleClear" Placeholder = "Node name..." />
</div>
</ColumnOptions>
</PropertyColumn>
<PropertyColumn Title = "Description" Property = "@(n => n.Description)" Sortable = "false" />
<TemplateColumn Title = "Servers" Align = "Align.Start">
<p @onclick = "@(() => OpenPanelRightAsync(@context.Servers[0]))">@context.Servers.Count</p>
</TemplateColumn>
<TemplateColumn Title = "" Align = "Align.Start">
<FluentIcon Value = "@(new Icons.Regular.Size24.Edit())" OnClick = "@(() => Edit(@context))" />
</TemplateColumn>
</FluentDataGrid>
}
@code {
// UI
private PaginationState pagination = new PaginationState { ItemsPerPage = 20 };
private bool showDialog = false;
private IDialogReference? _dialog;
// Nodes
IQueryable<S2IXNodeDto>? nodesGrid;
bool nodesFound = false;
// Filter
string nodeFilter = string.Empty;
IQueryable<S2IXNodeDto>? FilteredItems => nodesGrid?.Where(n => n.Name.Contains(nodeFilter, StringComparison.CurrentCultureIgnoreCase));
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
stateService.SetAddNode(false);
stateService.SetEditNode(false);
stateService.SetAddSelectedNode(null);
using (HttpClient httpClient = new HttpClient())
{
NodeClient nodeClient = new NodeClient(httpClient);
var result = await nodeClient.GetAllNodes();
nodesGrid = result.OrderBy(n => n.Name).AsQueryable();
nodesFound = nodesGrid.Any();
if (!nodesFound)
{
showDialog = true;
}
}
}
StateHasChanged();
}
private void Edit(S2IXNodeDto nodeDto)
{
stateService.SetAddSelectedNode(nodeDto);
stateService.SetEditNodeNetwork(true);
navMan.Refresh(true);
}
private void HandleClear()
{
if (string.IsNullOrEmpty(nodeFilter))
{
nodeFilter = string.Empty;
}
}
private void HandleNameFilter(ChangeEventArgs args)
{
if (args.Value is string value)
{
nodeFilter = value;
}
}
private async Task OpenPanelRightAsync(Guid server)
{
using (HttpClient httpClient = new HttpClient())
{
ServerClient serverClient = new ServerClient(httpClient);
ServerDto result = await serverClient.GetServer(server.ToString());
_dialog = await DialogService.ShowPanelAsync<SimpleServerPanel>(result, new DialogParameters<ServerDto>()
{
Content = result,
Title = $"Hello {result.Name}",
Alignment = HorizontalAlignment.Right,
PrimaryAction = "Close"
});
DialogResult panel = await _dialog.Result;
HandlePanel(panel);
}
}
private static void HandlePanel(DialogResult result)
{
if (result.Cancelled)
{
return;
}
if (result.Data is not null)
{
var server = result.Data as ServerDto;
return;
}
}
}
SimpleServerPanel.razor:
@implements IDialogContentComponent<ServerDto>
<FluentDialogBody>
<h3>Servers</h3>
<FluentTextField @bind-Value = "@Content.Name">This is a test:</FluentTextField>
</FluentDialogBody>
@code
{
[Parameter]
public ServerDto Content { get; set; } = default!;
}
Любая помощь будет принята с благодарностью!





Ответ заключался в том, что в моем MainLayout мне пришлось добавить @rendermode = "RenderMode.InteractiveServer" к FluentDialogProvider, например:
<FluentDialogProvider @rendermode = "RenderMode.InteractiveServer"/>
Жаль, что в документации об этом не упомянуто.
Собственно, это задокументировано. fluentui-blazor.net/DialogService