[Blazor] With MudBlazor

MudBlazor๋ฅผ ํ™œ์šฉํ•œ UI ๊ตฌ์„ฑ ์ง€์‹์„ ์ •๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

:pushpin: ํŽธ์˜์ƒ MudBlazor Template๋กœ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•ด์„œ ์ž‘์—…ํ•ฉ๋‹ˆ๋‹ค.

5๊ฐœ์˜ ์ข‹์•„์š”

๊ถ๊ธˆํ•˜๋„ค์š” ๊ธฐ๋Œ€

4๊ฐœ์˜ ์ข‹์•„์š”

์•—, ์ €๋„ ๊ด€์‹ฌ์žˆ์Šต๋‹ˆ๋‹ค. ใ…‹ใ…‹ใ…‹

3๊ฐœ์˜ ์ข‹์•„์š”

MudDialog

MudBlazor ๋ฌธ์„œ
https://mudblazor.com/components/dialog

Source code (GitHub)
https://github.com/ChoiHM/MB-MudDialogSample


๊ธฐ๋ณธ์ ์ธ ์‚ฌํ•ญ

Global ์„ค์ •

Shared>MainLayout.razor ํŒŒ์ผ์„ ์—ด์–ด์„œ ์ œ์ผ ์œ— ๋ถ€๋ถ„์„ ๋ด…๋‹ˆ๋‹ค.

@inherits LayoutComponentBase

<MudThemeProvider />
<MudDialogProvider /> @* <-- MudDialogProvider ์ธ์Šคํ„ด์Šค ์ •์˜ ๋ฐ Global setting *@
<MudSnackbarProvider />

์„ค์ •์€ ์•„๋ž˜์™€ ๊ฐ™์ด ๊ตฌ์ฒด์ ์œผ๋กœ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, Dialog ํ˜ธ์ถœ์‹œ ๋ณ„๋‹ค๋ฅธ ์˜ต์…˜์„ ์ง€์ •ํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด Global ์„ค์ •์„ ์ƒ์†๋ฐ›์Šต๋‹ˆ๋‹ค.

<MudDialogProvider
    FullWidth="true"
    MaxWidth="MaxWidth.ExtraSmall"
    CloseButton="true"
    DisableBackdropClick="true"
    NoHeader="true"
    Position="DialogPosition.Center"
    CloseOnEscapeKey="true"
/>


Dialog ํ˜ธ์ถœ

1. Dialog ์ž…๋ ฅ๊ฐ’ ๋ฆฌํ„ด

์ด์ œ ๊ฐ„๋‹จํ•˜๊ฒŒ ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•œ ๋ฒ„ํŠผ 2๊ฐœ๊ณผ Dialog ์ปดํฌ๋„ŒํŠธ๋„ 2๊ฐœ ๋งŒ๋“ค๊ฒ ์Šต๋‹ˆ๋‹ค.
ํŽ˜์ด์ง€๋Š” Index.razor๋ฅผ ๋Œ€์ถฉ ์ˆ˜์ •ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ฒ„ํŠผ์„ 2๊ฐœ ์ถ”๊ฐ€ํ•˜๊ณ  onclick ์ด๋ฒคํŠธ๋ฅผ ์—ฐ๊ฒฐํ•ฉ๋‹ˆ๋‹ค.

  • Index.razor
@page "/"
@inject IDialogService _dialogService
@using MudDialogSample.Dialog;

<PageTitle>Index</PageTitle>

<MudText Typo="Typo.h3" GutterBottom="true">Dialogํ…Œ์ŠคํŠธ</MudText>

<MudStack Row="true" Class="mb-5" Spacing="1">
    <MudButton Variant="Variant.Outlined" Size="Size.Small"
               @onclick="NewFolder">์ƒˆ ํด๋”</MudButton>

    <MudButton Variant="Variant.Outlined" Size="Size.Small"
               @onclick="NewFolderAsync">์ƒˆ ํด๋” Async</MudButton>

    <MudButton Variant="Variant.Outlined" Size="Size.Small" Color="Color.Info" StartIcon="@Icons.Material.Filled.CloudUpload"
               @onclick="Upload">์—…๋กœ๋“œ</MudButton>
</MudStack>

<MudText>ํด๋”๋ช…: @NewFolderName</MudText>

@code {
    private string NewFolderName = string.Empty;

    private void NewFolder()
    {
        // ๋ฆฌํ„ด๊ฐ’์ด ํ•„์š”ํ•˜๋‹ค๋ฉด Showํ•จ์ˆ˜๋กœ๋Š” ๋ฐ›์•„์˜ฌ ์ˆ˜ ์—†์–ด์š”!
        var dialog = _dialogService.Show<DlgNewFolder>("์ƒˆ ํด๋” ๋งŒ๋“ค๊ธฐ",
        new DialogOptions() { CloseOnEscapeKey = true });
        //var result = dialog.Result.Result;
    }

    private async void NewFolderAsync()
    {
        var dialog = await _dialogService.ShowAsync<DlgNewFolder>("์ƒˆ ํด๋” ๋งŒ๋“ค๊ธฐ",
        new DialogOptions() { CloseOnEscapeKey = true });
        var result = await dialog.Result;

        if (result == null || result.Canceled) { return; }
        if (result?.Data != null)
        {
            if (string.IsNullOrWhiteSpace(result.Data.ToString()))
            {
                return;
            }
            NewFolderName = result.Data.ToString();
            StateHasChanged();
        }
    }

    private async void Upload()
    {
    }
}

:pushpin: ShowAsync๋ฉ”์„œ๋“œ ์˜ค๋ฅ˜ ํ‘œ์‹œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•

MudTemplate์„ ์ด์šฉํ•ด์„œ ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑํ•˜๋ฉด, ๊ตฌ๋ฒ„์ „์ด ์„ค์น˜๋œ ๊ฒฝ์šฐ๊ฐ€ ๋งŽ์Šต๋‹ˆ๋‹ค.
๋”ฐ๋ผ์„œ ShowAsyncํ•จ์ˆ˜๊ฐ€ ์ œ๊ณต๋˜์ง€ ์•Š๋Š” ๋ฒ„์ „์„ ์‚ฌ์šฉํ•˜๋ฉด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ, ์•„๋ž˜์™€ ๊ฐ™์ด ์—…๋ฐ์ดํŠธ ํ•ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.
(์ €์˜ ๊ฒฝ์šฐ 6.0.13์ด ์„ค์น˜๋˜์–ด ์žˆ์œผ๋ฉฐ, 6.2.2๋กœ ์—…๋ฐ์ดํŠธ ์ง„ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.)


ํ”„๋กœ์ ํŠธ์— Dialog ํด๋”๋„ ํ•˜๋‚˜ ์ƒ์„ฑํ•˜์—ฌ Dialog์šฉ๋„๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค.
'์ƒˆ ํด๋”'๋ฅผ ์œ„ํ•œ ํ•ญ๋ชฉ์ด๋ฏ€๋กœ DlgNewFolder.razor๋กœ ์ƒ์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.

image

  • DlgNewFolder.razor ์†Œ์Šค์ฝ”๋“œ
<MudDialog DefaultFocus="DefaultFocus.FirstChild">
  <DialogContent>
      <MudForm ReadOnly="false">
          <MudTextField T="string" Label="ํด๋”๋ช…" @bind-Value="FolderName" Immediate="true" 
OnKeyDown="keydown"></MudTextField>
      </MudForm>
  </DialogContent>
  <DialogActions>
      <MudButton Color="Color.Primary" ButtonType="ButtonType.Submit"
OnClick="Submit">์ƒ์„ฑ</MudButton>
      <MudButton OnClick="Cancel">์ทจ์†Œ</MudButton>
  </DialogActions>
</MudDialog>

@code {
    [CascadingParameter] MudDialogInstance MudDialog { get; set; }
    [Parameter]
    public string FolderName { get; set; }

    void Submit() => MudDialog.Close(DialogResult.Ok(FolderName));
    void Cancel() => MudDialog.Cancel();

    private void keydown(KeyboardEventArgs e)
    {
        if (e.Key == "Enter")
        {
            MudDialog.Close(DialogResult.Ok(FolderName));
        }
    }
}

MudBlazor์—๋Š” FocusTrap์ด๋ผ๋Š” ๊ฐ์ฒด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด์™€ ๊ด€๋ จ๋œ ์„ค๋ช…์€ MudBlazor ๋ฌธ์„œ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.
๊ฐ„๋žตํ•˜๊ฒŒ ์„ค๋ช…๋“œ๋ฆฌ์ž๋ฉด MudDialog์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ FocusTrap์ด ๋“ค์–ด๊ฐ€ ์žˆ์–ด์„œ

<MudDialog DefaultFocus="DefaultFocus.FirstChild">

์ด๋ ‡๊ฒŒ DefaultFocus๋ฅผ FirstChild๋กœ ์„ธํŒ…๋งŒ ํ•ด์ฃผ์…”๋„ ๊ฐ์ฒด ๋‚ด๋ถ€์˜ ์ฒซ๋ฒˆ์งธ ์š”์†Œ์— ์ž๋™์œผ๋กœ ํฌ์ปค์Šค๊ฐ€ ์ƒ๊ธฐ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.
๋˜ํ•œ ์•„๋ž˜์™€ ๊ฐ™์ด ์ฒซ๋ฒˆ์งธ ์š”์†Œ์ธ TextField์— onkeydown ์ด๋ฒคํŠธ๋ฅผ ์ˆ˜์‹ ํ•จ์œผ๋กœ์จ, ์—”ํ„ฐํ‚ค์— ๋ฐ˜์‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ด๋†จ์Šต๋‹ˆ๋‹ค.

<MudTextField T="string" Label="ํด๋”๋ช…" @bind-Value="FolderName" Immediate="true" 
OnKeyDown="keydown"></MudTextField>

์ž! ์ด์ œ ์‹คํ–‰ํ•ด์„œ ํŽ˜์ด์ง€๋ฅผ ๋„์šฐ๊ณ  โ€˜์ƒˆ ํด๋” Asyncโ€™ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ๋ด…๋‹ˆ๋‹ค.
image

์ฒ˜์Œ ํฌ์ปค์Šค๊ฐ€ TextField๋กœ ๊ฐ€ ์žˆ์„๊ฒ๋‹ˆ๋‹ค.
DotNetDev ์ž…๋ ฅ ํ›„ ์—”ํ„ฐ!


image

:stopwatch: ์‹œ๊ฐ„ ๊ด€๊ณ„์ƒ โ€œDialog๋กœ ํŒŒ๋ผ๋ฏธํ„ฐ ๋„˜๊ฒจ์ฃผ๊ธฐโ€ (์—…๋กœ๋“œ ๋ฒ„ํŠผ)๋Š” ๋‹ค์Œ ์‹œ๊ฐ„์— ์ถ”๊ฐ€ํ•˜๋„๋ก ํ• ๊ฒŒ์š”! :blush:

5๊ฐœ์˜ ์ข‹์•„์š”

Dialog ์ปดํฌ๋„ŒํŠธ๋Š” ๊ตฌํ˜„์„ ์™„๋ฃŒํ–ˆ๊ณ , ์ด์ œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๋„˜๊ฒจ์ฃผ๋Š” DialogResult๋ฅผ ํŽ˜์ด์ง€์—์„œ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

// Dialog ์˜ต์…˜์„ ์„ค์ • ํ›„ DlgNewFolder ์„œ๋น„์Šค ์ธ์Šคํ„ด์Šค๋ฅผ ํ˜ธ์ถœํ•ฉ๋‹ˆ๋‹ค.
DialogOptions closeOnEscapeKey = new() { CloseOnEscapeKey = true };
var dialog = await DialogService.ShowAsync<DlgNewFolder>("์ƒˆํด๋” ๋งŒ๋“ค๊ธฐ", closeOnEscapeKey);
// ๋ฐ›์•„์˜จ ๊ฒฐ๊ณผ๊ฐ’ ์ €์žฅ
var result = await dialog.Result;

// cancel๋˜๊ฑฐ๋‚˜ ์˜ค๋ฅ˜๋กœ ์ธํ•ด null์ด ๋ฆฌํ„ด๋˜์—ˆ๋Š”์ง€ ํ™•์ธ
if (!result.Canceled && result.Data != null)
{
    string NewFolderName = result.Data.ToString();
}
2๊ฐœ์˜ ์ข‹์•„์š”

MudChipSet

MudBlazor ๋ฌธ์„œ
https://mudblazor.com/components/chipset#single-selection


๊ธฐ๋ณธ์ ์ธ ์‚ฌ์šฉ๋ฒ•์€ ์œ„ ๋งํฌ๋ฅผ ์ฐธ๊ณ ํ•ด์ฃผ์„ธ์š”.

์ˆœ์ • ์ƒํƒœ์˜ Chipset ๊ตฌํ˜„

<MudChipSet MultiSelection="true" Filter="true">
    <MudChip Text="์ฒดํฌ1" Class="rounded pa-2" Variant="Variant.Outlined"></MudChip>
    <MudChip Text="์ฒดํฌ2" Class="rounded pa-2" Variant="Variant.Outlined" Color="Color.Info"></MudChip>
    <MudChip Text="์ฒดํฌ3" Class="rounded pa-2" Variant="Variant.Outlined" Color="Color.Success"></MudChip>
    <MudChip Text="์ฒดํฌ4" Class="rounded pa-2" Variant="Variant.Outlined" Color="Color.Warning"></MudChip>
    <MudChip Text="์ฒดํฌ5" Class="rounded pa-2" Variant="Variant.Outlined" Color="Color.Secondary"></MudChip>
    <MudChip Text="์ฒดํฌ6" Class="rounded pa-2" Variant="Variant.Outlined" Color="Color.Primary"></MudChip>
    <MudChip Text="์ฒดํฌ7" Class="rounded pa-2" Variant="Variant.Outlined" Color="Color.Dark"></MudChip>
</MudChipSet>

๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๋ณด์‹œ๋‹ค์‹œํ”ผ Chipset์˜ ํญ์ด ๋ณ€ํ•˜๋ฉด์„œ UI์ƒ์— ๋ณ€์ˆ˜๊ฐ€ ์ƒ๊ธธ ์ˆ˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

Animation1

๊ทธ๋ž˜์„œ ์ €๋Š” ์‹œ์ธ์„ฑ๋„ ์ข‹์œผ๋ฉด์„œ, ํญ์ด ๋ณ€ํ•˜์ง€ ์•Š๋„๋ก ์ฒดํฌ๋ฐ•์Šค๋ฅผ ์—†์• ๊ธฐ๋กœ ํ–ˆ์Šต๋‹ˆ๋‹ค.


๋ณ€ํ˜•๋œ ์Šคํƒ€์ผ์˜ Chipset ๊ตฌํ˜„

MudChipSet์˜ ํ•˜์œ„ ์š”์†Œ์— AvatarContent ๋ผ๋Š” ๊ฒƒ์ด ์žˆ์Šต๋‹ˆ๋‹ค.
์ด ์˜์—ญ์ด ์ฒดํฌ๋ฐ•์Šค์— ํ•ด๋‹นํ•˜๋Š” ์•„์ด์ฝ˜์ด ํ‘œ์‹œ๋˜๋Š” ์˜์—ญ์ธ๋ฐ, ํญ์„ 0์œผ๋กœ ๋งŒ๋“ค๋ฉด ๊ฐ„๋‹จํžˆ ํ•ด๊ฒฐ๋ฉ๋‹ˆ๋‹ค.
(๋” ์ข‹์€ ๋ฐฉ๋ฒ•์€ ์–ธ์ œ๋“  ๋Œ“๊ธ€๋กœ ๋‚จ๊ฒจ์ฃผ์„ธ์š”:smile:)

 <MudChipSet MultiSelection="true" Filter="true">
	 <MudChip Text="์ ‘์ˆ˜" Class="rounded mx-0 pa-2" Variant="Variant.Text" Color="Color.Transparent" SelectedColor="Color.Dark">
		 <AvatarContent>
			 <MudAvatar Style="width:0px;"></MudAvatar>
		 </AvatarContent>
	 </MudChip>
	 <MudChip Text="์ฒ˜๋ฆฌ์ค‘" Class="rounded mx-0 pa-2" Variant="Variant.Text" Color="Color.Transparent" SelectedColor="Color.Primary">
		 <AvatarContent>
			 <MudAvatar Style="width:0px;"></MudAvatar>
		 </AvatarContent>
	 </MudChip>
	 <MudChip Text="๋ฐฉ๋ฌธ์˜ˆ์ •" Class="rounded mx-0 pa-2" Variant="Variant.Text" Color="Color.Transparent" SelectedColor="Color.Success">
		 <AvatarContent>
			 <MudAvatar Style="width:0px;"></MudAvatar>
		 </AvatarContent>
	 </MudChip>
	 <MudChip Text="์‚ฌ๊ณ ์ฒ˜๋ฆฌ์ค‘" Class="rounded mx-0 pa-2" Variant="Variant.Text" Color="Color.Transparent" SelectedColor="Color.Warning">
		 <AvatarContent>
			 <MudAvatar Style="width:0px;"></MudAvatar>
		 </AvatarContent>
	 </MudChip>
	 <MudChip Text="์—ฐ๊ธฐ" Class="rounded mx-0 pa-2" Variant="Variant.Text" Color="Color.Transparent" SelectedColor="Color.Secondary">
		 <AvatarContent>
			 <MudAvatar Style="width:0px;"></MudAvatar>
		 </AvatarContent>
	 </MudChip>
	 <MudChip Text="์ฒ˜๋ฆฌ์™„๋ฃŒ" Class="rounded mx-0 pa-2" Variant="Variant.Text" Color="Color.Transparent" SelectedColor="Color.Tertiary">
		 <AvatarContent>
			 <MudAvatar Style="width:0px;"></MudAvatar>
		 </AvatarContent>
	 </MudChip>
	 <MudChip Text="์ทจ์†Œ" Class="rounded mx-0 pa-2" Variant="Variant.Text" Color="Color.Transparent" SelectedColor="Color.Error">
		 <AvatarContent>
			 <MudAvatar Style="width:0px;"></MudAvatar>
		 </AvatarContent>
	 </MudChip>
 </MudChipSet>

๊ฒฐ๊ณผ๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

Animation

3๊ฐœ์˜ ์ข‹์•„์š”