작업을 하다 보면 "지금 화면에 다이얼로그가 하나라도 떠 있는가?"를 알아야 할 때가 있다. 단축키를 막거나, 백그라운드 동작을 멈추거나, 특정 UI를 숨기는 등 용도는 다양하다. 문제는 이 상태를 어느 화면에서든 알고 싶다는 점이다. 컴포넌트마다 플래그를 들고 다니는 건 답이 아니다.
이번 글에서는 MudBlazor의 IDialogService를 활용해 다이얼로그 열림 상태를 전역으로 추적하는 방법을 정리한다. 특히 Blazor SSR 환경에서 마주치는 두 가지 함정과 그 해결책을 함께 다룬다.
MudBlazor의 IDialogService는 다이얼로그 생명주기에 대한 이벤트를 제공하는데 이를 이용하면 된다.
public class DialogTracker : IDisposable
{
private readonly IDialogService _dialogService;
// 현재 열려 있는 다이얼로그 개수
private int _count;
public DialogTracker(IDialogService dialogService)
{
_dialogService = dialogService;
_dialogService.DialogInstanceAddedAsync += OnAddedAsync;
}
// 하나라도 떠 있으면 true
public bool IsOpen => _count > 0;
private Task OnAddedAsync(IDialogReference reference)
{
// 다이얼로그 열림 → 카운트 증가 (스레드 안전)
Interlocked.Increment(ref _count);
// 닫힘 감지는 Result Task에 맡김 (await 결과는 무시)
_ = WaitForCloseAsync(reference);
// 비동기 이벤트지만 여기서 기다릴 게 없으므로 완료된 Task 반환
return Task.CompletedTask;
}
private async Task WaitForCloseAsync(IDialogReference reference)
{
// 닫히는 방식과 무관하게 다이얼로그가 닫히면 Result가 완료됨
await reference.Result;
// 닫힘 → 카운트 감소
Interlocked.Decrement(ref _count);
}
public void Dispose()
{
// 이벤트 구독 해제
_dialogService.DialogInstanceAddedAsync -= OnAddedAsync;
}
}
먼저 짚어야 할 사실. 정적(static) SSR에서는 MudBlazor 다이얼로그가 동작하지 않는다. 다이얼로그를 열고 닫는 건 런타임 상호작용이므로 InteractiveServer 같은 인터랙티브 렌더 모드가 필요하다. 즉, 다이얼로그가 실제로 뜬다는 건 그 영역이 이미 인터랙티브로 돌고 있다는 뜻이다.
여기서 SSR 특유의 함정이 나온다. 정적 SSR 스코프와 인터랙티브 회로(circuit) 스코프는 서로 다른 DI 스코프다. Scoped 서비스라도 두 영역에서 인스턴스가 따로 생성된다.
그래서 이런 일이 벌어진다.
해결의 핵심은 간단하다. 다이얼로그 이벤트가 발생하는 곳과 IsOpen을 읽는 곳이 같은 인터랙티브 렌더 모드 영역 안에 있어야 한다. 앱 전체를 글로벌 인터랙티브로 구성했다면 회로 스코프가 세션 내내 유지되므로 신경 쓸 일이 거의 없다. 부분 인터랙티브를 섞어 쓴다면, 추적기를 inject하는 컴포넌트가 다이얼로그와 동일한 인터랙티브 영역에 있는지 확인해야 한다.
등록은 Scoped로 한다.
builder.Services.AddScoped<DialogTracker>();
다이얼로그를 여는 코드는 전혀 바꿀 필요없이 평소처럼 호출하면 추적기가 알아서 잡는다.
@inject IDialogService DialogService
<MudButton OnClick="OpenDialog">열기</MudButton>
@code {
private async Task OpenDialog()
{
// 평소대로 호출하면 끝. 추적은 DialogTracker가 알아서 함
await DialogService.ShowAsync<MyDialog>("제목");
}
}
상태를 확인하고 싶은 곳에서는 DialogTracker를 inject해서 IsOpen만 읽으면 된다.
@inject DialogTracker Tracker
@if (Tracker.IsOpen)
{
<MudText>다이얼로그가 떠 있습니다</MudText>
}
DialogTracker는 한 번은 inject되어 인스턴스화돼야 생성자에서 이벤트 구독이 걸린다. 어디서도 inject하지 않으면 객체 자체가 생성되지 않아 추적이 시작되지 않는다. 그래서 회로 내내 살아있는 MainLayout 같은 컴포넌트에 inject해 두는 것을 권장한다. 값을 직접 쓰지 않아도 인스턴스화 자체가 목적이다.
@* MainLayout.razor *@
@inject DialogTracker Tracker
@* 인스턴스화만 시키면 되므로 화면에서 직접 쓰지 않아도 됨 *@
| Blazor SSR MarkupString XSS 막는 방법 (0) | 2026.03.30 |
|---|---|
| Blazor에서 브라우저 우클릭 메뉴 / F12 개발자 도구 막는 방법 (0) | 2026.03.11 |
| BlazorDatasheet 에서 대문자 / 소문자만 입력되도록 처리하기 (0) | 2026.02.02 |
| Blazor 메뉴 그룹 관리하기 (0) | 2025.12.28 |
| Blazor 인쇄 막는 방법 (0) | 2025.12.17 |