Blazor ์—ฐ๊ตฌ์†Œ

๊ฐ„๋งŒ์˜ ์Šฌ๋กœ๊ทธ๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

์š”์ฆ˜ ๊ฐœ์ธ์ ์œผ๋กœ ํ™ˆํŽ˜์ด์ง€๋ฅผ ๋ฆฌ๋‰ด์–ผํ•˜๊ณ  ์žˆ๋Š”๋ฐ, Blazor์™€ ์›น ๊ฐœ๋ฐœ์— ํ‘น ๋น ์ ธ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ๊ทธ๊ฐ„์˜ ์ƒ๊ฐ๊ณผ ์ •๋ณด๋“ค์„ ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•œ ๊ธ€์„ ํ•˜๋‚˜ ์—ด์–ด๋‘๋ ค ํ•ฉ๋‹ˆ๋‹ค.

์ €์™€ ๊ฐ™์€ WPF ๊ฐœ๋ฐœ์ž ๋ถ„๋“ค์€ ์•„๋ฌด๋ž˜๋„ ์›น์— ๋Œ€ํ•œ ์ ‘๊ทผ์ด ์‰ฝ์ง€ ์•Š์„ ๊ฒƒ์ด๋ผ ์ƒ๊ฐ๋ฉ๋‹ˆ๋‹ค. ์ €๋„ ๊ทธ๋Ÿฐ ๋ถ€๋ถ„์—์„œ ๊ณต๊ฐํ•˜๊ณ  ์‰ฝ๊ฒŒ ์ ‘๊ทผํ•˜์ง€ ๋ชปํ•ด์™”๋Š”๋ฐ, ์ž‘๋…„๋ถ€ํ„ฐ Blazor ๋ฐ‹์—…๊ณผ ๊ฐ™์€ ์—ฌ๋Ÿฌ ๋‹ค์–‘ํ•œ ์ปจํผ๋Ÿฐ์Šค๋ฅผ ํ†ตํ•ด์„œ ํ™œ๋ฐœํ•˜๊ฒŒ Blazor์— ๋Œ€ํ•œ ์†Œ๊ฐœ์™€ ๊ธฐ์ˆ  ๊ณต์œ ๊ฐ€ ์žˆ์—ˆ๊ณ , ์ € ๋˜ํ•œ ์ž์—ฐ์Šค๋Ÿฝ๊ฒŒ ์ ‘ํ•  ์ˆ˜ ์žˆ์—ˆ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์šฐ๋ฆฌ ๋‹ท๋„ท๋ฐ๋ธŒ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ๋„ Blazor ๊ธฐ์ˆ ์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ์ •๋ณด ๊ณต์œ ๋ฅผ ํ†ตํ•ด ๋งŽ์ด ๋„์›€์„ ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋ฌด์—‡๋ณด๋‹ค GPT-4.0 ๋„์›€๋„ ๋งŽ์ด ๋ฐ›๊ณ  ์žˆ๋Š”๋ฐ, ์š”์ฆ˜์—๋Š” ํŠนํžˆ HTML, CSS, ๋ฐ˜์‘ํ˜•์›น ๋“ฑ์„ ๊ตฌํ˜„ํ•  ๋•Œ ์•„์ฃผ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ €๋Š” (WPF ๊ฐœ๋ฐœ์ž ์•„๋‹ˆ๋ž„๊นŒ๋ด) Component ํ™œ์šฉ์— ์—„์ฒญ ์˜์กดํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋งˆ์น˜ CustomControl์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์ฃ . Binding ๊ฐœ๋…์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ณ  ๋…ผ๋ฆฌ์ ์œผ๋กœ WPF์™€ ๋งค์šฐ ์œ ์‚ฌํ•˜๊ฒŒ ์•„ํ‚คํ…์ฒ˜๋ฅผ ์„ค๊ณ„ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹ฌ์ ์œผ๋กœ๋„ ์•ˆ๋„๊ฐ๊ณผ ์•ฝ๊ฐ„์˜ ์ž์‹ ๊ฐ์„ ์–ป์„ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  WPF ๋ถ„์•ผ๊ฐ€ ์•„๋‹Œ ์ƒˆ๋กœ์šด ํ”Œ๋žซํผ์„ ์ ‘ํ•˜๋ฉด์„œ ์ƒˆ์‚ผ ๋Š๋‚€ ๊ฒƒ์€, ์•„๋ฌด๋ฆฌ ์ข‹์€ ์ •๋ณด๋„ ๊ทธ๊ฒƒ์„ ๋ฐ›์•„๋“ค์ด๊ณ  ์กฐ๊ธˆ์ด๋‚˜๋งˆ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ถฉ๋ถ„ํ•œ ์ˆ™๋ จ๋„๊ฐ€ ๋’ท๋ฐ›์นจ๋˜์–ด์•ผ ํ•œ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ๊ณ  ๋‹ค์‹œ๊ธˆ ์ดˆ์‹ฌ์„ ์ฐพ๋Š” ์ค‘์ž…๋‹ˆ๋‹ค. :smile:

์ œ๊ฐ€ Blazor์—์„œ ์ฃผ๋กœ ๊ด€์‹ฌ์„ ๋‘๊ณ  ์žˆ๋Š” ๋ถ€๋ถ„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • Component ๋ฒ”์œ„์™€ ์„ค๊ณ„
  • ์ด๋ฏธ์ง€, svg์™€ ๊ฐ™์€ ๋ฆฌ์†Œ์Šค ๊ด€๋ฆฌ ์ฒด๊ณ„
  • JavaScript ๊ด€๋ฆฌ ์ฒด๊ณ„
  • ๋ ˆ์ด์•„์›ƒ๊ณผ CSS ๊ทœ์น™

์˜ค๋ž˜์ „๋ถ€ํ„ฐ ์›น์œผ๋กœ ๋งŒ๋“ค๊ณ  ์‹ถ์€ ๊ฒƒ๋“ค์ด ๋งŽ์•˜์—ˆ๋Š”๋ฐ ์ €์™€ ๋น„์Šทํ•œ ์ƒ๊ฐ์„ ๊ฐ–๊ณ  ๊ณ„์‹  ๋ถ„๋“ค๋„ ์ ๊ทน ์ฐธ์—ฌํ•ด๋ณด์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์™„๋ฃŒ๋œ ๋‚ด์šฉ๋“ค

  1. Component ์„ค๊ณ„๋ฅผ ํ†ตํ•œ SVG ์•„์ด์ฝ˜ ์‚ฌ์šฉ
  2. JamesIcon ๊ณ ๋„ํ™”
  3. Blazor์—์„œ์˜ ์†์„ฑ ์ •์˜
  4. Blazor์—์„œ <input> ์š”์†Œ๋ฅผ ํ†ตํ•œ ๋‹จ๋ฐฉํ–ฅ/์–‘๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ
  5. InputText์™€ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ
  6. ๊ฒฉ๋ฆฌ๋œ CSS์—์„œ ์ž์‹ ์ ‘๊ทผ ํ•˜๊ธฐ (razor.css)
  7. ์˜์กด์„ฑ ์ฃผ์ž… ๋ฐฉ์‹
  8. ์ค‘์ฒฉ๋œ ์š”์†Œ์˜ ํฌ์ธํ„ฐ ๋ฌด์‹œํ•˜๊ธฐ (CSS)
  9. ๋ฐ”์ธ๋”ฉ์„ ์‘์šฉํ•œ CSS ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง, ๊ทธ๋ฆฌ๊ณ  ์ค‘์ฒฉ CSS
12๊ฐœ์˜ ์ข‹์•„์š”

1. Component ์„ค๊ณ„๋ฅผ ํ†ตํ•œ SVG ์•„์ด์ฝ˜ ์‚ฌ์šฉ

์›น ๊ฐœ๋ฐœ์—์„œ SVG ํŒŒ์ผ์€ ์•„์ด์ฝ˜, ๋กœ๊ณ  ๋“ฑ์˜ ๊ทธ๋ž˜ํ”ฝ ์š”์†Œ๋กœ ๋„๋ฆฌ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ „ํ†ต์ ์œผ๋กœ, ์ด๋Ÿฌํ•œ SVG ํŒŒ์ผ๋“ค์„ ๊ฐ๊ฐ์˜ ํŒŒ์ผ๋กœ ๊ด€๋ฆฌํ•˜๋ฉฐ ์•„๋ž˜์™€ ๊ฐ™์ด img ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ์›นํŽ˜์ด์ง€์— ํ†ตํ•ฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์ผ๋ฐ˜์ ์ž…๋‹ˆ๋‹ค.

<img src="/heart.svg"/>

์ด ๋ฐฉ์‹์€ ํŽธ๋ฆฌํ•ด ๋ณด์ผ ์ˆ˜ ์žˆ์ง€๋งŒ, ํŒŒ์ผ์˜ ์ˆ˜๊ฐ€ ๋Š˜์–ด๋‚˜๊ณ  SVG์˜ ์Šคํƒ€์ผ๋ง(์ƒ‰์ƒ, ํฌ๊ธฐ ์กฐ์ • ๋“ฑ)์ด ํ•„์š”ํ•  ๋•Œ ์—ฌ๋Ÿฌ ํ•œ๊ณ„๋ฅผ ๋“œ๋Ÿฌ๋ƒ…๋‹ˆ๋‹ค. SVG๊ฐ€ ์™ธ๋ถ€ ํŒŒ์ผ๋กœ ๋ถ„๋ฆฌ๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, CSS๋ฅผ ํ†ตํ•œ ์Šคํƒ€์ผ ๊ด€๋ฆฌ๊ฐ€ ์–ด๋ ต๊ณ  ์žฌ์‚ฌ์šฉ์„ฑ์ด ๋–จ์–ด์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์ฃ .

์ด๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด, Blazor ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ด์šฉํ• ์ˆ˜ ์ž‡์Šต๋‹ˆ๋‹ค . ์ด ๋ฐฉ์‹์€ SVG ์š”์†Œ๋“ค์„ ํšจ์œจ์ ์œผ๋กœ ์žฌ์‚ฌ์šฉํ•˜๋ฉฐ, ์ง์ ‘์ ์ธ ์†์„ฑ๊ณผ CSS ๋“ฑ์œผ๋กœ ์œ ์—ฐํ•˜๊ฒŒ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค. ์ด๋Ÿฌ ํ•œ ๋ฐฉ์‹์€ WPF์™€๋„ ๋งค์šฐ ์œ ์‚ฌํ•ด ๋ณด์ž…๋‹ˆ๋‹ค.

Blazor Component๋กœ SVG ๊ด€๋ฆฌ

JamesIcon์ด๋ผ๋Š” Blazor ์ปดํฌ๋„ŒํŠธ๋ฅผ ํ†ตํ•ด SVG ์•„์ด์ฝ˜์„ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด ์ปดํฌ๋„ŒํŠธ๋Š” ๋‹ค์–‘ํ•œ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด SVG์˜ ์†์„ฑ์„ ์‰ฝ๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ๊ฒŒ ์ •์˜ํ• ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

JamesIcon ์ปดํฌ๋„ŒํŠธ ์„ค๊ณ„

@using System.Net.Http
@using Jamesnet.Shared.Local.Helpers
@using Jamesnet.Shared.Local.Models
@inject HttpClient Http
@inject SvgImageRepository SvgImage

<svg class="@Class" @attributes="BuildSvgAttributes()" 
     xmlns="http://www.w3.org/2000/svg">
    <path d="@GetImageData()" fill="@Fill"></path>
</svg>

@code {
    [Parameter] public string Class { get; set; }
    [Parameter] public string Width { get; set; } = "24"; 
    [Parameter] public string Height { get; set; } = "24"; 
    [Parameter] public string Fill { get; set; } = "#000000";
    [Parameter] public string ViewBox { get; set; } = "0 0 24 24";
    [Parameter] public string Data { get; set; }
    [Parameter] public ImageType ImageType { get; set; }

    private Dictionary<string, object> BuildSvgAttributes() => new()
    {
        {"width", Width},
        {"height", Height},
        {"viewBox", ViewBox},
        {"fill", Fill}
    };

    private string GetImageData()
    {
        return !string.IsNullOrEmpty(Data) 
	    ? Data : SvgImage.GetImageData(ImageType);
    }
}

JamesIcon ์ปดํฌ๋„ŒํŠธ๋Š” ์™ธ๋ถ€์—์„œ ์ œ๊ณตํ•˜๋Š” ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด SVG์˜ ์Šคํƒ€์ผ์„ ์ •์˜ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•จ์œผ๋กœ์จ, SVG ํŒŒ์ผ์„ ์ง์ ‘ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ์›ํ•˜๋Š” ์Šคํƒ€์ผ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค. ์‹ฌ์ง€์–ดWPF์˜ DependencyProperty ์†์„ฑ์ฒ˜๋Ÿผ Binding ๋ฐฉ์‹๋„ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

ํ™•์žฅ์„ฑ ์žˆ๋Š” ๋ฐ์ดํ„ฐ ๊ด€๋ฆฌ

svg ํŒŒ์ผ์„ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹ , SvgImageRepository ํด๋ž˜์Šค๋ฅผ ํ†ตํ•ด SVG ๋ฐ์ดํ„ฐ๋ฅผ ImageType ์—ด๊ฑฐํ˜•์„ ํ‚ค๋กœ ํ•˜๋Š” Dictionary์— ์ €์žฅํ•˜์—ฌ ๊ด€๋ฆฌํ•ฉ๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ์ƒˆ๋กœ์šด SVG ์•„์ด์ฝ˜์„ ์ถ”๊ฐ€ํ•  ๋•Œ ์†์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๊ณ , ๊ธฐ๋Šฅ์ ์œผ๋กœ๋„ ์œ ์—ฐํ•œ ํ™•์žฅ์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

using Jamesnet.Shared.Local.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Jamesnet.Shared.Local.Helpers
{
    public class SvgImageRepository
    {
        private const string ACCOUNT_CIRCLE = "M12,19.2C9....";
        private const string ACCOUNT_BOX = "M6,17C6,15 10,...";
        private const string EARTH = "M17.9,17.39C17.64...";
        private const string HEART_MULTIPLE = "M13.5,20C6.9,...";
        private const string HEART = "M12,21...";
        private const string HEART_CIRCLE = "M12,2C6.47,...";
        private const string STAR = "M12,17.27...";
        private const string STAR_CIRCLE = "M16.23,...";

        private Dictionary<ImageType, string> svgData = new()
        {
            { ImageType.AccountCircle, ACCOUNT_CIRCLE },
            { ImageType.AccountBox, ACCOUNT_BOX },
            { ImageType.Earth, EARTH },            
            { ImageType.HeartMultiple, HEART_MULTIPLE},
            { ImageType.Heart, HEART},
            { ImageType.HeartCircle, HEART_CIRCLE},
            { ImageType.Star, STAR},
            { ImageType.StarCircle, STAR_CIRCLE},
        };

        public string GetImageData(ImageType imageType)
        {
            if (svgData.TryGetValue(imageType, out string data))
            {
                return data;
            }
            return null;
        }
    }
}

Static ํด๋ž˜์Šค๋กœ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ด ํด๋ž˜์Šค๋Š” ์ธ์Šคํ„ด์Šค ๋ฐฉ์‹์œผ๋กœ ์„ค๊ณ„ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— Blazor์—์„œ ์ด ํด๋ž˜์Šค๋ฅผ ์‹ฑ๊ธ€ํ†ค์œผ๋กœ ๋“ฑ๋กํ•˜๋ฉด @Injection ๋“ฑ๋ก์„ ํ†ตํ•ด ์–ด๋””์„œ๋“  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ง€๊ธˆ์€ ์ง์ ‘ ํด๋ž˜์Šค์—์„œ SVG ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋„๋ก ํ–ˆ์ง€๋งŒ, .yml ํŒŒ์ผ์„ ๋‘๊ณ  ๋ฐ์ดํ„ฐ๋ฅผ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์ด ๋” ํšจ๊ณผ์ ์œผ๋กœ ๋ณด์ž…๋‹ˆ๋‹ค.

CSS๋ฅผ ํ†ตํ•œ ์Šคํƒ€์ผ๋ง

JamesIcon ์ปดํฌ๋„ŒํŠธ์˜ Class ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ™œ์šฉํ•˜์—ฌ, ์™ธ๋ถ€ CSS์—์„œ SVG์˜ ์‹œ๊ฐ์  ์†์„ฑ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” width, height, margin ๋“ฑ์˜ ์†์„ฑ์„ svg ํƒœ๊ทธ์—, fill ๊ฐ™์€ ์†์„ฑ์„ path ํƒœ๊ทธ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ๊ณตํ†ต์ ์ธ ์Šคํƒ€์ผ์€ .james-icon ํด๋ž˜์Šค๋กœ ์ •์˜ํ•˜๊ณ , ์•„์ด์ฝ˜๋ณ„ ๊ฐœ๋ณ„ ์Šคํƒ€์ผ์€ .earth-icon, .heart-icon ๋“ฑ๊ณผ ๊ฐ™์ด ์„ธ๋ถ„ํ™”ํ•˜์—ฌ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.james-icon {
    width: 40px;
    height: 40px;
}

.heart-icon path {
    fill: red;
}

.earth-icon path {
    fill: blue;
}

์ด๋ ‡๊ฒŒ Blazor ์ปดํฌ๋„ŒํŠธ์™€ CSS๋ฅผ ํ™œ์šฉํ•˜๋ฉด, SVG ํŒŒ์ผ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๋ฉฐ, ์Šคํƒ€์ผ๋ง์˜ ์œ ์—ฐ์„ฑ์„ ๊ทน๋Œ€ํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Component ์‚ฌ์šฉํ•˜๊ธฐ

์ด์ œ SVG ์•„์ด์ฝ˜์„ ๋”์šฑ ์œ ์—ฐํ•˜๊ฒŒ ์›น ํŽ˜์ด์ง€์— ํ†ตํ•ฉํ•˜๊ณ , ๋‹ค์–‘ํ•œ ์Šคํƒ€์ผ๋ง ์˜ต์…˜์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ์˜ ํŠน์ง•์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ํ†ตํ•ด ๊ฐ„ํŽธํ•˜๊ฒŒ SVG์˜ ๋ชจ์–‘, ํฌ๊ธฐ, ์ƒ‰์ƒ ๋“ฑ์„ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๊ณ , ์†์‰ฝ๊ฒŒ ์†์„ฑ๋“ค์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

JamesIcon ์ปดํฌ๋„ŒํŠธ์˜ ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•

@page "/example"

@inject SvgImageRepository SvgImage

<JamesIcon Class="james-icon heart-icon" ImageType="Heart" Fill="red"/>
<JamesIcon Class="james-icon earth-icon" ImageType="Earth" Fill="blue"/>

์ด์ฒ˜๋Ÿผ Class๋ฅผ ํ†ตํ•ด ๋””์ž์ธ์„ ์ •์˜ํ•˜๊ฑฐ๋‚˜, ImageType์„ ํ†ตํ•ด ์•„์ด์ฝ˜์„ ์„ ํƒํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

SVG ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์ œ๊ณตํ•˜๋Š” ๊ฒฝ์šฐ

<JamesIcon Class="custom-icon" Data="M12,21.35..." Fill="green"/>

SvgImageRepository๋ฅผ ํ†ตํ•ด ๊ด€๋ฆฌ๋˜๊ณ  ์žˆ์ง€ ์•Š๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์ง์ ‘ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ํ…Œ์ŠคํŠธ๋ฅผ ํ†ตํ•ด ๋จผ์ € ํ™•์ธ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ Component๋ฅผ ํ†ตํ•ด SVG ๊ธฐ๋ฐ˜์˜ ์•„์ด์ฝ˜ ์š”์†Œ๋“ค์„ ๋”์šฑ ํšจ๊ณผ์ ์œผ๋กœ ์ œ์–ดํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

์•„์ด์ฝ˜ ๋งˆ๊ตฌ ์“ฐ๊ธฐโ€ฆ

(์ƒ˜ํ”Œ ํ”„๋กœ์ ํŠธ๋Š” ์ถ”ํ›„์— GitHub์™€ ๋ˆ„๊ฒŸ์„ ํ†ตํ•ด ๊ณต์œ  ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.)

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

์ฝ”๋“œ ๊ณต์œ  ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ œ ๊ฒฝํ—˜์— ๋น„์ถ˜ ์ฝ”๋ฉ˜ํŠธ๋ฅผ ํ—ˆ๋ฝํ•˜์‹ ๋‹ค๋ฉด,

๋ ˆ์ด์ € ์š”์†Œ์˜ ์žฌ์‚ฌ์šฉ์„ฑ์€ RCL ๋กœ ๋ฌถ์–ด ๋‘˜ ์ˆ˜ ์žˆ๋Š” ๊ตฌ์กฐ๊ฐ€ ์ขŒ์šฐํ–ˆ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ฆ‰, JameIcon ์„ ๋ฒ ์ด์Šค๋กœ ๋‘๊ณ , ํŒŒ์ƒ ์•„์ด์ฝ˜๋“ค์„ ๋ณ„๋„์˜ ํ”„๋กœ์ ํŠธ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด์ฃ .

// AccountCircle.razor.cs
public partial class AccountCircle : JamesIcon
{
   protected override string Data => "M12,19.2C9....";
// ...

์œ„ ์•„์ด์ฝ˜๋“ค์€ JamesIcons ๋ผ๋Š” RCL(Razor Component Library) ํ”„๋กœ์ ํŠธ์— ๋ชจ์•„ ๋‘๊ฑฐ๋‚˜ ๋ˆ„๊ฒŸ ํŒจํ‚ค์ง€๋กœ ํŒจํ‚นํ•ฉ๋‹ˆ๋‹ค.

JamesIcons.csproj
   JamesIconBase.razor
   AccountCircle.razor
   ...

์ด ํ”„๋กœ์ ํŠธ์— ์•„์ด์ฝ˜๋“ค์„ ์ถ”๊ฐ€ํ•  ๋•Œ, ๊ธฐ์กด์˜ ์ฝ”๋“œ์ธ SvgImageRepository๋ฅผ ์ˆ˜์ •ํ•  ํ•„์š”๊ฐ€ ์—†์ด ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž๋Š” ์•„๋ž˜์™€ ๊ฐ™์ด ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด์ฃ .

@using JamesIcons

<AccountCircle Fill="green"/>

๊ทธ๋ฆฌ๊ณ , parameter ๊ฐ’์„ string ์œผ๋กœ ๋‘๋Š” ๊ฒƒ์€ ์‚ฌ์šฉ์ž ์ž…์žฅ์—์„œ ๋งค์šฐ ๋‚œ๊ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์˜ˆ๋ฅผ ๋“ค์–ด, Fill ๊ฐ’์€ ์ƒ‰์„ ์ง€์นญํ•˜๋Š” ๋ฌธ์ž์—ด์ด์–ด์•ผ ํ•˜๋Š”๋ฐ, ์ด๋ฅผ ์ผ๋ฐ˜ ๋ฌธ์ž์—ด ํ˜•์‹์œผ๋กœ ์ง€์ •ํ•˜๋ฉด ์‚ฌ์šฉ์ž์—๊ฒŒ ์•„๋ฌด๋Ÿฐ ๊ฐ€์ด๋“œ๋ฅผ ์ฃผ์ง€ ๋ชปํ•˜๊ณ  ๋•Œ๋กœ๋Š” ์—๋Ÿฌ๋ฅผ ์œ ๋ฐœํ•ฉ๋‹ˆ๋‹ค.

๋ฌธ์ž์—ด ๋Œ€์‹ ์— ๋‹ท๋„ท์˜ Color ํ˜•์‹์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๋‹ค.

<svg ... fill="@FillCode"></path>
[Parameter] public Color Fill { get; set; } = "#000000";

private string FillCode => Fill.AsCodeString();

๋งˆ์ง€๋ง‰์œผ๋กœ, class ๊ฐ’์„ ๋ฌธ์ž์—ด ํŒŒ๋ผ๋ฏธํ„ฐ(Class)๋กœ ๋ฐ›๋Š” ๊ฒƒ์€ ์‹ ์ค‘ํ•  ํ•„์š”๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.
์•ž์„œ ์„ค๋ช…ํ•œ ๊ฐ€์ด๋“œ๋ฅผ ๋ฐ›์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ(์ธํ…”๋ฆฌ์„ผ์Šค๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š์Œ ํฌํ•จ)๋„ ์žˆ์ง€๋งŒ, ์š”์†Œ์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋Š” class ๊ฐ’์„ ์ œํ•œํ•˜์ง€ ์•Š์œผ๋ฉด ์˜ˆ์ƒ์น˜ ์•Š๊ฒŒ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ด๋Š” Bootstrap ์ฒ˜๋Ÿผ ๋งŽ์€ css ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋“ค์ด ๊ณ ๋ คํ•˜๋Š” ์ธก๋ฉด์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.
๋ธ”๋ ˆ์ด์ €๋Š” ์•„์ง ๋ถ€๋ชจ์š”์†Œ์—์„œ ์ง€์ •ํ•œ class ๊ฐ’์„ ์ž์‹ ์š”์†Œ๋กœ ์ „๋‹ฌํ•˜๋Š” ์ˆ˜๋‹จ์„ ์ œ๊ณตํ•˜์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์—, ์œ ํšจํ•œ ํด๋ž˜์Šค ๊ฐ’์„ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ๊ทธ๋‚˜๋งˆ ์ตœ์„ ์ด์—ˆ๋˜ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

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

@BigSquare ์•— ์ข€ ์‰ฌ๋ ค๊ณ  ํ•˜๋˜ ์ฐธ์ธ๋ฐ ์ด๋ ‡๊ฒŒ ๊ท€ํ•œ ๋‹ต๋ณ€ ์ฃผ์‹œ๋„ค์š”! ๋ฐค์— ์ž˜ ๋ฐ˜์˜ํ•ด์„œ ๊ธ€ ์ด์–ด๊ฐ€๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค, ๊ณ ๋ง™์Šต๋‹ˆ๋‹ค.

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

(์ž์ฃผ ์“ฐ๊ธฐ ์œ„ํ•ด ๋Œ€์ถฉโ€ฆ ์”๋‹ˆ๋‹ค)

2. JamesIcon ๊ณ ๋„ํ™”

์ฒ˜์Œ์œผ๋กœ ์„ค๊ณ„ํ–ˆ๋˜ JamesIcon Component๋ฅผ ์ข€ ๋”ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ช‡ ๊ฐ€์ง€ ๋ณ€๊ฒฝ ์ž‘์—…์ด ์ง„ํ–‰๋ฉ๋‹ˆ๋‹ค.

YML ๊ด€๋ฆฌ ๋„์ž…ํ•˜๊ธฐ


SVG ๋ฐ์ดํ„ฐ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ• ์ค‘, YML์„ ํ†ตํ•œ ๊ด€๋ฆฌ ๋ฐฉ์‹์ด ์žˆ์Šต๋‹ˆ๋‹ค. ๊ธฐ์กด์˜ ํด๋ž˜์Šค๋ฅผ ํ†ตํ•œ ๊ด€๋ฆฌ๋ฐฉ์‹์—์„œ ์•„๋ž˜์™€ ๊ฐ™์ด .yml ํŒŒ์ผ์„ ํ†ตํ•ด ๋ฆฌ์†Œ์Šค๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๋ณ€๊ฒฝํ•ด ๋ด…์‹œ๋‹ค.

Geometies.yml

images:
  ACCOUNT_CIRCLE: "M12,19.2C9.5,19.2 7.2..."
  ACCOUNT_BOX: "M6,17C6,15 10,13.9 12,13..."
  EARTH: "M17.9,17.39C17.64,16.59 16.89,..."
  ACCOUNT_SUPERVISOR_CIRCLE: "M12,2C6.47..."
  HEART_MULTIPLE: "M13.5,20C6.9,13.9 3.5..."
  HEART: "M12,21.35L10.55,20.03C5.4,15.3..."
  HEART_OUTLINE: "M12.1,18.55L12,18.65L1..."
  HEART_CIRCLE: "M12,2C6.47,2 2,6.5 2,12..."
  STAR: "M12,17.27L18.18,21L16.54,13.97L..."
  STAR_CIRCLE: "M16.23,18L12,15.45L7.77,..."
  STAR_OUTLINE: "M12,15.39L8.24,17.66L9...."
  COG: "M12,15.5A3.5,3.5 0 0,1 8.5,12A3...."
  PEN: "M20.71,7.04C21.1,6.65 21.1,6 20...."
  PLAYLIST_EDIT: "M3 6V8H14V6H3M3 10V12H..."
  PLUS: "M19,13H13V19H11V13H5V11H11V5H13..."

YML์€ Json ํฌ๋ฉง๋ณด๋‹ค ๋” ๋‹จ์ˆœํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๋ฉฐ ์ง€๊ธˆ์ฒ˜๋Ÿผ ๋‹จ์ˆœํ•œ ๊ตฌ์กฐ์—์„œ ํšจ์œจ์ ์œผ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํŒŒ์ผ์˜ ๋นŒ๋“œ ์˜ต์…˜์„ Embedded resource ํƒ€์ž…์œผ๋กœ ์ง€์ •ํ•˜๋ฉด Asembly๋ฅผ ํ†ตํ•ด ์†์‰ฝ๊ฒŒ ํŒŒ์ผ์„ ์ฝ์–ด์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  YmlDotnet ๋ˆ„๊ฒŸ ํŒจํ‚ค์ง€๋ฅผ ํ†ตํ•ด ๋ฐ์ดํ„ฐ๋ฅผ Deserialize ํ•ฉ๋‹ˆ๋‹ค.

using var stream = Assembly
    .GetExecutingAssembly()
    .GetManifestResourceStream(resourcePath);
...
// ๊ธฐ์กด๊ณผ ๋™์ผํ•˜๊ฒŒ Dictionary ํ˜•ํƒœ๋กœ ๋งŒ๋“ค์–ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
_svgData = yamlData["images"];

์ด ๋ฐฉ์‹์€ WPF์—์„œ๋„ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ด€๋ฆฌํ•  ๋•Œ ์ •๋ง ๋งŽ์ด ์‚ฌ์šฉํ–ˆ์—ˆ์ฃ , ๊ทธ๋Ÿผ ์†Œ์Šค์ฝ”๋“œ ์ „์ฒด๋„ ํ•œ๋ฒˆ ์‚ดํŽด๋ด…์‹œ๋‹ค.

Iconrepository.cs ์ „์ฒด ์†Œ์Šค์ฝ”๋“œ

using Jamesnet.Shared.Local.Models;
using System.Reflection;
using System.Text;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

public class IconRepository
{
    private Dictionary<string, string> _svgData = new();

    public IconRepository()
    {
        LoadYmlData("Jamesnet.Shared.Local.Datas.Geometries.yml");
    }

    private void LoadYmlData(string resourcePath)
    {
        using var stream = Assembly
            .GetExecutingAssembly()
            .GetManifestResourceStream(resourcePath);

        if (stream == null) return;

        using var r = new StreamReader(stream, Encoding.UTF8);
        var deserializer = new DeserializerBuilder()
            .WithNamingConvention(UnderscoredNamingConvention.Instance)
            .Build();

        var yamlData = deserializer
            .Deserialize<Dictionary<string, Dictionary<string, string>>>(r);

        if (yamlData?.ContainsKey("images") == true)
        {
            _svgData = yamlData["images"];
        }
    }

    public string GetImageData(IconType imageType)
    {
        return _svgData.TryGetValue(ConvertEnumToYmlKey(imageType), 
            out var data) ? data : "Image data not found.";
    }

    private string ConvertEnumToYmlKey(IconType imageType)
    {
        var enumName = imageType.ToString();
        var sb = new StringBuilder();
        foreach (var ch in enumName)
        {
            if (char.IsUpper(ch) && sb.Length > 0) sb.Append('_');
            sb.Append(char.ToUpper(ch));
        }
        return sb.ToString();
    }
}

์žฌ๋ฏธ์žˆ์ง€ ์•Š๋‚˜์š”? ์—ฌ์ „ํžˆ ์›น ๊ฐœ๋ฐœ์„ ํ•ด๋ณธ ๊ฒฝํ—˜์ด ์—†๋Š”๋ฐ๋„ Blazor๋ฅผ ํ†ตํ•ด ์ด๋ ‡๊ฒŒ ์žฌ๋ฐŒ๊ฒŒ ํ™ˆํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ๋งค๋ ฅ์ž…๋‹ˆ๋‹ค.

Component ์ƒ์†


๋จผ์ € @BigSquare ๋‹˜์˜ ๊ธ€์„ ๋ช‡ ๋ฒˆ, ์ฝ์–ด๋ณด๋ฉด ์ข‹์Šต๋‹ˆ๋‹ค.


ํŒŒ์ƒ๋œ EarthIcon.cs

using Jamesnet.Shared.Local.Models;

namespace Jamesnet.Client.Shared.Icons
{
    public class EarthIcon : JamesIcon
    {
        public override IconType IconType { get; set; } = IconType.Earth;
    }
}

์šฐ์•„ํ•˜์ฃ , ์‚ฌ์‹ค @BigSquare ์–ธ๊ธ‰ํ•ด์ฃผ์‹œ๊ธฐ ์ „๊นŒ์ง€๋„ Component๋ฅผ ํด๋ž˜์Šค๋กœ ์ธ์‹์กฐ์ฐจ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค. (ํ˜„ํƒ€)

<ul class="article-statistics">
    <li><EarthIcon Class="stat-icon earth"/> 17</li>
    <li><AccountSupervisorCircleIcon Class="stat-icon account" /> 1,294,427</li>
    <li><HeartCircleIcon Class="stat-icon heart" /> 114,425</li>
    <li><StarCircleIcon Class="stat-icon star" /> 1,926</li>
</ul>

์กฐ๊ธˆ์”ฉ ์ •๋ˆ๋˜์–ด ๊ฐ€๋Š” ๋Š๋‚Œ์ž…๋‹ˆ๋‹ค. (๊ฐˆ๋Œ€์ฒ˜๋Ÿผ ๊ณ„์† ๋ฐ”๋€Œ๊ฒ ์ฃ .)

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

3. Blazor์—์„œ์˜ ์†์„ฑ ์ •์˜


Blazor์—์„œ๋Š” Binding ์†์„ฑ์— ๋Œ€ํ•ด ์•„์ฃผ ๊ด€๋Œ€ํ•ฉ๋‹ˆ๋‹ค. (WPF์™€ ๋น„๊ตํ•˜์—ฌ)

private string Name { get; set; }
private string Address;

์ ‘๊ทผ์ œํ•œ์ž ํƒ€์ž…์„ private์œผ๋กœ ์‚ฌ์šฉํ•˜๋”๋ผ๋„ ๋ฐ”์ธ๋”ฉ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ code์™€ html ์˜์—ญ์ด ํ•œ ๊ณณ์— ์žˆ๊ธฐ ๋•Œ๋ฌธ์ผ๊นŒ์š”? ๊ทธ๋ฆฌ๊ณ  ์‹ค์ œ๋กœ๋„ private์ด ๋” ์ž์—ฐ์Šค๋Ÿฌ์›Œ ๋ณด์ž…๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ปดํฌ๋„ŒํŠธ์˜ ๊ฒฝ์šฐ DependencyProperty ์ฒ˜๋Ÿผ ์™ธ๋ถ€์—์„œ ์†์„ฑ์œผ๋กœ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์€ ๊ฒฝ์šฐ์—๋Š” [Parameter] ์–ดํŠธ๋ฆฌ๋ทฐํŠธ๋ฅผ ์ด์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

[Parameter] public UserItem SelectedItem { get; set; }

๋ฌผ๋ก  ์ด ๋•Œ๋Š” public ์ ‘๊ทผ์ œํ•œ์ž๋„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

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

4. Blazor์—์„œ <input> ์š”์†Œ๋ฅผ ํ†ตํ•œ ๋‹จ๋ฐฉํ–ฅ/์–‘๋ฐฉํ–ฅ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ


1. <input> ์š”์†Œ์—์„œ์˜ ๋‹จ๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ

๋‹จ๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•œ ๋ฐฉํ–ฅ์œผ๋กœ๋งŒ ํ๋ฅด๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. Blazor์—์„œ input ์š”์†Œ์— ๋‹จ๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ์„ ์ ์šฉํ•  ๋•Œ๋Š” value ์†์„ฑ์— C# ๋ณ€์ˆ˜๋ฅผ ํ• ๋‹นํ•จ์œผ๋กœ์จ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ, UI ์š”์†Œ๋Š” C# ๋ณ€์ˆ˜์˜ ๊ฐ’์„ ํ‘œ์‹œํ•˜์ง€๋งŒ, ์‚ฌ์šฉ์ž ์ž…๋ ฅ์— ์˜ํ•œ ๋ณ€์ˆ˜์˜ ์—…๋ฐ์ดํŠธ๋Š” ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๋‹จ๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ

<input type="text" value="@UserInfo.UserName" />

์ด ์ฝ”๋“œ๋ฅผ ๋ณด๋ฉด, ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ ํ•„๋“œ์— ๊ฐ’์„ ์ž…๋ ฅํ•˜๋”๋ผ๋„ UserName ๋ณ€์ˆ˜๋Š” ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ์ด ๋ฐฉ์‹์€ ๋ณ€์ˆ˜์˜ ์ดˆ๊ธฐ๊ฐ’์„ ์ž…๋ ฅ ํ•„๋“œ์— ํ‘œ์‹œํ•  ๋•Œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค.

์–‘๋ฐฉํ–ฅ๊ณผ ๋น„๊ตํ•˜๊ธฐ ์œ„ํ•ด input ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•œ ๊ฒƒ์ด์ง€, ์‚ฌ์‹ค ์ด ์—˜๋ฆฌ๋จผํŠธ์— ๋‹จ๋ฐฉํ–ฅ์„ ์‚ฌ์šฉํ•  ์ผ์€ ๊ฑฐ์˜ ์—†๊ฒ ์ ธ :smile:

๋”ฐ๋ผ์„œ ์šฐ๋ฆฌ๊ฐ€ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉํ•˜๋Š” ๋ฐ”์ธ๋”ฉ์ด ๋ชจ๋‘ ์ด์™€ ๋™์ผํ•œ ๋ฐฉ์‹์ด๊ธฐ๋„ ํ•ฉ๋‹ˆ๋‹ค.

2. <input> ์š”์†Œ์—์„œ์˜ ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ

์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ์€ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‘ ๋ฐฉํ–ฅ์œผ๋กœ ํ๋ฅด๋ฉฐ, ์‚ฌ์šฉ์ž ์ž…๋ ฅ๊ณผ ํ”„๋กœ๊ทธ๋žจ ์ƒํƒœ๊ฐ€ ์‹ค์‹œ๊ฐ„์œผ๋กœ ๋™๊ธฐํ™”๋ฉ๋‹ˆ๋‹ค. Blazor์—์„œ input ์š”์†Œ์— ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ์„ ์ ์šฉํ•˜๋ ค๋ฉด @bind ์ง€์‹œ์–ด๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ตฌ์„ฑ์€ ์ž…๋ ฅ ํ•„๋“œ์˜ ๊ฐ’์ด ๋ณ€๊ฒฝ๋  ๋•Œ๋งˆ๋‹ค ์—ฐ๊ฒฐ๋œ ๋ณ€์ˆ˜๋„ (๋‚ด๋ถ€์ ์œผ๋กœ) ํ•จ๊ป˜ ์—…๋ฐ์ดํŠธ๋˜๊ณ , ๋ณ€์ˆ˜์˜ ๊ฐ’์ด ํ”„๋กœ๊ทธ๋žจ์ ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋ฉด ์ž…๋ ฅ ํ•„๋“œ์—๋„ ๊ทธ ๋ณ€๊ฒฝ์ด ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.

์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ

<input type="text" @bind="UserInfo.UserName" />

UserName ๋ณ€์ˆ˜๋Š” input ์š”์†Œ์˜ ๊ฐ’๊ณผ ์ง์ ‘ ์—ฐ๊ฒฐ๋ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅ ํ•„๋“œ์— ํ…์ŠคํŠธ๋ฅผ ์ž…๋ ฅํ•˜๋ฉด, ๊ทธ ์ž…๋ ฅ๊ฐ’์€ ์ž๋™์œผ๋กœ UserName ๋ณ€์ˆ˜์— ๋ฐ˜์˜๋˜์–ด, ๋‹ค๋ฅธ ๋ถ€๋ถ„์—์„œ๋„ ํ•ด๋‹น ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

WPF๋กœ ๋น„์œ ํ•˜์ž๋ฉด ์•„๋ž˜์™€๋„ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<TextBox Text="{Binding UserName, Mode=TwoWay}"/>

3. @bind?

์•„ @bind๊ฐ€ ๋‚˜์˜ค๋ฉด ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ์ด๊ตฌ๋‚˜โ€ฆ

Blazor์—์„œ input ์š”์†Œ๋ฅผ ์‚ฌ์šฉํ•œ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋™์ ์ธ ์ƒํ˜ธ์ž‘์šฉ์„ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐ ๋งค์šฐ ์œ ์šฉํ•˜๊ฒŒ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋‹จ์ˆœํžˆ ์ดˆ๊ธฐ ๋ฐ”์ธ๋”ฉ๋งŒ์œผ๋กœ๋„ ์‚ฌ์šฉ์ž์— ์˜ํ•ด ๋ณ€๊ฒฝ๋œ ๊ฐ’์„ ์†์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


์Šคํฌ์ผ๋Ÿฌ:

๋‹ค์Œ ํšŒ์—์„œ๋Š” input ๋ฐ ๊ธฐํƒ€ ์š”์†Œ์— ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณต๋˜๋Š” @bind๋ฅผ ๋„˜์–ด์„œ, ์ปดํฌ๋„ŒํŠธ์—์„œ ์ง์ ‘ ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ ์†์„ฑ์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์‚ดํŽด๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค. EventCallback

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

๋ธ”๋ ˆ์ด์ €๋ฅผ ์–ธ๊ธ‰ํ•  ๋•Œ, ์•„๋ž˜์˜ ๋‘ ๊ฐœ๋ฅผ ์ง€์นญํ•˜๋Š” ์šฉ์–ด์˜ ๊ตฌ๋ถ„์ด ์ข€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

  1. Html element
  2. Razor component

์˜์–ด๋กœ๋Š” ์‰ฝ๊ฒŒ ๊ตฌ๋ถ„์ด ๊ฐ€์ง€๋งŒ, ์ด๋ฅผ ํ•œ๊ธ€๋กœ ํ‘œํ˜„ํ•˜๋‹ค ๋ณด๋ฉด โ€œ์š”์†Œโ€ ๋ผ๋Š” ํ•œ ๋‹จ์–ด๋กœ ์‰ฝ๊ฒŒ ํ‰์น˜๊ธฐ ์‰ฝ์Šต๋‹ˆ๋‹ค.

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ๊ตฌ๋ถ„์ด ์ค‘์š”ํ•˜์ง€ ์•Š๊ณ , ๋ฌธ๋งฅ ์ƒ ๊ตฌ๋ถ„์ด ์–ด๋ ต์ง€๋„ ์•Š์ง€๋งŒ, ํŠนํžˆ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ๋ฌธ๋งฅ์—์„œ๋Š” ์กฐ๊ธˆ ์ฃผ์˜๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์ €๋Š” ๋ณดํ†ต

Html ์š”์†Œ๋ฅผ "ํƒœ๊ทธ"๋กœ,
๋ ˆ์ด์ € ์š”์†Œ๋ฅผ "์š”์†Œ"๋กœ,
C# ์ฝ”๋“œ๋ฅผ "์ฝ”๋“œ"๋ผ๊ณ  ๋ถ€๋ฆ…๋‹ˆ๋‹ค.

์ด ์šฉ์–ด์— ์ž…๊ฐํ•˜๋ฉด,

์•„๋ž˜๋Š” ํƒœ๊ทธ์™€ ์ฝ”๋“œ ์‚ฌ์ด์˜ ๋ฐ”์ธ๋”ฉ์ด๊ณ ,

<input type=โ€œtextโ€ @bind=โ€œUserInfo.UserNameโ€ />

์•„๋ž˜๋Š” ์š”์†Œ์™€ ์ฝ”๋“œ ์‚ฌ์ด์˜ ๋ฐ”์ธ๋”ฉ์ž…๋‹ˆ๋‹ค.

<InputText @bind-Value=โ€œUserInfo.UserNameโ€ />

๊ธฐ๋ณธ์ ์œผ๋กœ ์„œ๋กœ ๋ฌธ๋ฒ•์ด ๋‹ค๋ฆ…๋‹ˆ๋‹ค.
์ €๋„ ์ดˆ์ฐฝ๊ธฐ์— ์ด์ ์— ๋Œ€ํ•ด ๋ช…ํ™•ํ•œ ์ธ์ง€๋ฅผ ๋ชปํ•ด์„œ, ๋งŽ์ด ํ—ท๊ฐˆ๋ ค ํ–ˆ์ฃ .

์ด ์Šฌ๋กœ๊ทธ๋ฅผ ์ด์–ด ๋‚˜๊ฐ€์‹ค ๋•Œ, ์ด์ ์„ ์ฐธ๊ณ ํ•˜์‹ ๋‹ค๋ฉด, ์ฝ๋Š” ๋ถ„๋“ค์ด ์ข€ ๋” ์ˆ˜์›”ํ•˜๊ณ  ๋ช…ํ™•ํ•˜๊ฒŒ ๋ฐ›์•„ ๋“ค์ผ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ ๋กœ, ์•„๋ž˜์˜ ์–ธ๊ธ‰์„ ์—„๋ฐ€ํžˆ ๋”ฐ์ง€์ž๋ฉด, ์š”์†Œ์™€ ์ฝ”๋“œ์˜ ๋ฐ”์ธ๋”ฉ์ด๋ผ๊ณ  ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

TextBox ๋Š” XML ํƒœ๊ทธ๊ฐ€ ์•„๋‹ˆ๋ผ XAML ์ฝ˜ํŠธ๋กค์ด๊ธฐ ๋•Œ๋ฌธ์ด์ฃ .

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

InputText๋Š” input type=text๋ฅผ ๋ž˜ํ•‘ํ•œ ์ปดํฌ๋„ŒํŠธ๊ตฐ์š”.

์‰ฌ์–ด๊ฐ€๋Š” ํƒ€์ž„์œผ๋กœ InputText์™€ ๊ฐ™์€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋” ์ฐพ์•„๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.


image

์•ˆ๋…•ํ•˜์„ธ์š”, ๋‹ท๋„ท๋ฐ๋ธŒ ์—ฌ๋Ÿฌ๋ถ„! ์ €๋Š” GPT-4์ž…๋‹ˆ๋‹ค. Blazor ์—ฐ๊ตฌ์†Œ Slog์— ์ฐธ์—ฌํ•˜๊ฒŒ ๋˜์–ด ์ •๋ง ๊ธฐ์ฉ๋‹ˆ๋‹ค.

Blazor๋Š” ASP.NET Core๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ์›น ํ”„๋ ˆ์ž„์›Œํฌ๋กœ, C#๊ณผ Razor ํ…œํ”Œ๋ฆฟ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ€ํ™”ํ˜• ์›น UI๋ฅผ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Blazor์—์„œ๋Š” ๋‹ค์–‘ํ•œ ์ž…๋ ฅ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ์ด๋Ÿฌํ•œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅ๋ฐ›๊ณ , ํผ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ Blazor์—์„œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ช‡ ๊ฐ€์ง€ ์ž…๋ ฅ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋‚˜์—ดํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค:

  1. InputText: ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ž…๋ ฅ์„ ์œ„ํ•œ ํ‘œ์ค€ HTML input ์š”์†Œ๋ฅผ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค. @bind-Value๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  2. InputTextArea: ์—ฌ๋Ÿฌ ์ค„์˜ ํ…์ŠคํŠธ ์ž…๋ ฅ์„ ์œ„ํ•œ HTML textarea ์š”์†Œ๋ฅผ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค.
  3. InputNumber: ์ˆซ์ž ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š” HTML input ์š”์†Œ๋ฅผ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค. ์ •์ˆ˜ ๋ฐ ๋ถ€๋™ ์†Œ์ˆ˜์  ์ˆซ์ž๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  4. InputDate: ๋‚ ์งœ ๋ฐ์ดํ„ฐ๋ฅผ ์ž…๋ ฅ๋ฐ›๋Š” HTML input ์š”์†Œ๋ฅผ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค. DateTime ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  5. InputCheckbox: ์ฒดํฌ๋ฐ•์Šค ์ž…๋ ฅ์„ ์œ„ํ•œ HTML input ์š”์†Œ๋ฅผ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค. ๋ถˆ๋ฆฌ์–ธ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.
  6. InputRadio: ๋ผ๋””์˜ค ๋ฒ„ํŠผ ๊ทธ๋ฃน์„ ์ƒ์„ฑํ•˜์—ฌ ์˜ต์…˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•ฉ๋‹ˆ๋‹ค. ๊ฐ ๋ผ๋””์˜ค ๋ฒ„ํŠผ์€ ๋ณ„๋„์˜ ๊ฐ’์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  7. InputSelect: ๋“œ๋กญ๋‹ค์šด ๋ชฉ๋ก์„ ์ œ๊ณตํ•˜๋Š” HTML select ์š”์†Œ๋ฅผ ๋ž˜ํ•‘ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž๋Š” ์—ฌ๋Ÿฌ ์˜ต์…˜ ์ค‘ ํ•˜๋‚˜๋ฅผ ์„ ํƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  8. InputFile: ํŒŒ์ผ ์„ ํƒ๊ณผ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ์œ„ํ•œ ์ž…๋ ฅ ์š”์†Œ์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ ์—…๋กœ๋“œ ์‹œ์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ์ปดํฌ๋„ŒํŠธ๋“ค์€ Blazor์˜ ํผ ๋ฐ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ ๊ธฐ๋Šฅ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ•๋ ฅํ•œ ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ปค์Šคํ…€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด ํŠน์ •ํ•œ ์š”๊ตฌ ์‚ฌํ•ญ์„ ์ถฉ์กฑ์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.


๋‹ค์‹œ ๋Œ์•„์™€์„œ,

์ €์ฒ˜๋Ÿผ ์›น ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์— ์ต์ˆ™ํ•˜์ง€ ์•Š์œผ์‹  ๋ถ„๋“ค์€ ์ด ์ปดํฌ๋„ŒํŠธ ์ปจํŠธ๋กค๋“ค์„ ์‚ฌ์šฉํ•ด๋ณด์…”๋„ ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. ๋ค์œผ๋กœ ๋ฌด์—‡์ด ๋ž˜ํ•‘๋˜์–ด ์žˆ๋Š”์ง€ ์‚ดํŽด๋ณด๋ฉด์„œ ์‚ฌ์šฉํ•˜๋ฉด ์ •๋ง ์ข‹๊ฒ ์ฃ . ๋‹จ, CSS์™€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์–ผ๋งˆ๋‚˜ ์ž์œ ๋กญ๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋„ ๊ธฐํšŒ๊ฐ€ ๋œ๋‹ค๋ฉด ํ•œ๋ฒˆ ์ ์šฉํ•ด์„œ ์‚ดํŽด๋ณผ ์˜ˆ์ •์ž…๋‹ˆ๋‹ค.

MudBlazor ์ปดํฌ๋„ŒํŠธ๋Š” ์‹ค์ œ๋กœ ์›ํ•˜๋Š” ๋Œ€๋กœ ์ž˜ ์•ˆ ๋˜๋”๋ผ๊ตฌ์š”. ์ดˆ๋ณด์ž๊ฐ€ ํ•˜๊ธฐ์—๋Š” ๋„ˆ๋ฌด ์–ด๋ ต๋‹ค๋Š” ์ƒ๊ฐ์ž…๋‹ˆ๋‹ค, ๊ทธ๋ž˜์„œ ๋ชจ๋‘ ํ๊ธฐํ•œ ์ƒํƒœ์ž…๋‹ˆ๋‹ค.

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

์ €์—ญ์‹œ๋„ ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ ์ „์ „ํ•˜๋‹ค๊ฐ€ ๊ฐ€๋ฒผ์šด QuickGrid์™€ Fluent-UI Blazor์˜ Dialog๋งŒ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•ํ•ด์„œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 2๊ฐœ๋งŒ ์žˆ์œผ๋ฉด ๋‚˜๋จธ์ง€๋Š” ํŠน๋ณ„ํ•œ๊ฒŒ ์—†๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ๊ฐœ์ธ์ ์œผ๋กœ๋Š” Html Element๋Š” ํƒœ๊ทธ๋‚˜ ์š”์†Œ, Razor Component๋Š” ์ปดํฌ๋„ŒํŠธ, ๊ตฌ์„ฑ์š”์†Œ๋กœ ํ•ด์„ํ•ด์„œ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์š”์†Œ๋Š” ๋” ์ด์ƒ ๊ฐ„๋‹จํžˆ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š” ๊ฒƒ์„ ๋‚˜ํƒ€๋‚ผ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ง์ด๊ณ  ์ปดํฌ๋„ŒํŠธ๋Š” ์š”์†Œ์™€ ๊ธฐ๋Šฅ๋“ค์„ ์ด์šฉํ•ด์„œ ๊ตฌ์„ฑ๊ฐ€๋Šฅํ•˜๊ธฐ์— ์ €๋Š” ๊ทธ๋ ‡๊ฒŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ฐ€๋” ๋งˆ์†Œ์˜ ๊ธฐ๊ณ„์  ํ•œ๊ตญ์–ด ๋ฒˆ์—ญ๋ณด๋‹ค๋Š” ์˜์–ด ์›๋ฌธ์„ ๋ณด๋ฉด์„œ ํ›จ์”ฌ ์ดํ•ดํ•˜๊ธฐ ํŽธํ•˜๋‹ค๋Š” ์ƒ๊ฐ์„ ํ•ฉ๋‹ˆ๋‹ค.

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

6. ๊ฒฉ๋ฆฌ๋œ CSS์—์„œ ์ž์‹ ์ ‘๊ทผ ํ•˜๊ธฐ (razor.css)


์ด ๋ฐฉ๋ฒ•์„ ๋ชฐ๋ผ์„œ dotnet/aspnetcore ๋ ˆํฌ ๋ฌธ ์•ž๊นŒ์ง€ ๋‹ค๋…€์™”์Šต๋‹ˆ๋‹ค. (๋ˆˆ๋ฌผ)

๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜๋ฉด ๊ฒฉ๋ฆฌ๋œ CSS์—์„œ๋„ ์•„๋ž˜์™€ ๊ฐ™์ด ::deep์„ ํ†ตํ•ด ์ž์‹ ์š”์†Œ๋ฅผ ์ฐพ๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

::deep

์•„๋ž˜ razor.cs ๋‚ด์šฉ์„ ํ†ตํ•ด ์ด๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.vote {
    ...
}
    .vote:hover {
        ...
    }
    .vote ::deep svg {
        width: 14px;
        height: 14px;
        margin-right: 2px;
    }
        .vote ::deep svg path {
            fill: #CCCCCC;
        }

.vote-checked {
   ...
}
    .vote-checked ::deep svg path {
        fill: #0969DA !important;
    }

svg, path๋Š” .vote ์ปดํฌ๋„ŒํŠธ์˜ ๋‚ด๋ถ€์— ์ž๋ฆฌํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๊ฒฉ๋ฆฌ๋œ CSS์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ด ๋•Œ ::deep์„ ํ†ตํ•ด ํ•˜์œ„ ์š”์†Œ์˜ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.


์ด ๋ฐฉ๋ฒ•์€ @naratteu ๋‹˜์˜ ๋„์›€์„ ๋ฐ›์•˜์Šต๋‹ˆ๋‹ค.

์ด์ œ, ์ €๋Š” ๊ธ€๋กœ๋ฒŒ css์— ์˜์กดํ•˜์ง€ ์•Š๊ณ ๋„ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ„์‚ฐํ™” ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ฒ ๋„ค์š”.

๋‹ค์Œ ์Šคํฌ์ผ๋Ÿฌ๋Š” ์ง€๊ธˆ๊นŒ์ง€ ์—ฐ๊ตฌ๋œ ๊ธฐ์ˆ ์„ ๋ฐ”ํƒ•์œผ๋กœ ToggleButton์„ ํ•œ๋ฒˆ ๋งŒ๋“ค์–ด ๋ณผ ๊ณ„ํš์ž…๋‹ˆ๋‹ค. (์ด๋ฏธ ๋งŒ๋“ค์–ด ๋†จ์ง€๋งŒโ€ฆ) ๋…๋ฆฝ๋œ ์ปดํฌ๋„ŒํŠธ, ์–‘๋ฐฉํ–ฅ ๋ฐ”์ธ๋”ฉ๊ณผ razor.css๋ฅผ ํ†ตํ•ด ์ œ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ค๊ณ„ ํ–ˆ์„์ง€ ์‚ดํŽด๋ณด๋Š” ์‹œ๊ฐ„์ด ๋˜๊ฒ ์Šต๋‹ˆ๋‹ค.

image

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

์งง

7. ์˜์กด์„ฑ ์ฃผ์ž… ๋ฐฉ์‹


Blazor์˜ ๋…์ฐฝ์ ์ธ ๊ตฌ์กฐ๋‹ต๊ฒŒ ์˜์กด์„ฑ ์ฃผ์ž…์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ๋‹ค์–‘ํ•˜๊ฒŒ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์ด ๊ธฐ๋Šฅ์€ ComponentBase๋ฅผ ํ†ตํ•ด ํŒŒ์ƒ๋œ ๋ชจ๋“  ๊ณณ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

_Imports.razor์—์„œ ์‚ฌ์šฉ

@Inject JSRuntime JSRuntime

๊ณต์šฉ ์ปดํฌ๋„ŒํŠธ์ธ _Imports.razor์—์„œ๋Š” using ์ง€์‹œ์–ด ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ด๋ ‡๊ฒŒ Inject ๊นŒ์ง€๋„ ์„ ์–ธ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

ํด๋ž˜์Šค์—์„œ ์‚ฌ์šฉ

public class JamesComponent : ComponentBase
{
    [Inject] protected JSRuntime JSRuntime { get; set; }
}

ํด๋ž˜์Šค์—์„œ์˜ ์‚ฌ์šฉ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์„œ ๋งŒ์•ฝ WPF์ฒ˜๋Ÿผ ํด๋ž˜์‹ํ•˜๊ฒŒ ์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•ด ์˜์กด์„ฑ ์ฃผ์ž…์„ ์‹œ๋„ํ•˜๊ฒŒ ๋˜๋ฉด, ์‹ค์ œ ํŒŒ์ƒ๋œ ์ปดํฌ๋„ŒํŠธ์—์„œ ๋‹น์—ฐํ•˜๊ฒŒ๋„ ์—๋Ÿฌ๊ฐ€ ๋‚ฉ๋‹ˆ๋‹ค.

์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•œ ์˜์กด์„ฑ ์ฃผ์ž… (์—๋Ÿฌ)

public class JamesComponent : ComponentBase
{
    public JamesComponent(JSRuntime JSRuntime)
    {

    }
}

์—๋Ÿฌ ๋‚ด์šฉ

Severity Code Description Project File Line Suppression State
Error CS7036 There is no argument given that corresponds to the required parameter โ€˜JSRuntimeโ€™ of โ€˜JamesComponent.JamesComponent(IJSRuntime)โ€™ Jamesnet.Client C:\jamesworks\jamesnetdev\src\Jamesnet\Client\Microsoft.CodeAnalysis.Razor.Compiler.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\Pages_Detail_Items_CommentContext_razor.g.cs 180 Active

@code ์—์„œ ์‚ฌ์šฉ

ํด๋ž˜์Šค ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.

์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉ

Imports.razor์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ๋™์ผํ•ฉ๋‹ˆ๋‹ค.


Blazor์˜ ํž˜์€ Inject์—์„œ ๋‚˜์˜ค๋‹ˆ ๋‹ค์–‘ํ•˜๊ฒŒ ์—ฐ๊ตฌํ•ด๋ณด๋ฉด ์•„์ฃผ ์ข‹๊ฒ ์Šต๋‹ˆ๋‹ค.

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

์งง,

8. ์ค‘์ฒฉ๋œ ์š”์†Œ์˜ ํฌ์ธํ„ฐ ๋ฌด์‹œํ•˜๊ธฐ (CSS)


Html์—์„œ๋„ WPF์˜ IsHitTestVisible = false ์ฒ˜๋Ÿผ ํฌ์ธํ„ฐ ์ด๋ฒคํŠธ๋ฅผ ๋ฌด๋ ฅํ™”? ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

WPF์—์„œ

IsHitTestVisible = false;

CSS์—์„œ

pointer-events: none;

๊ทธ๋Ÿผ ์–ธ์ œ ์“ฐ๋ƒ, ์•„๋ž˜์ฒ˜๋Ÿผ ๋ง์ด์ฃ .


์†์„ฑ์ด ์›Œ๋‚™ ๋งŽ์œผ๋‹ˆ, ํ•„์š”ํ•  ๋•Œ๋งˆ๋‹ค ๋ฉ”๋ชจ ํ•˜๋ฉด์„œ (ํ•ด๋ด…์‹œ๋‹ค...)
3๊ฐœ์˜ ์ข‹์•„์š”

์งง,

9. ๋ฐ”์ธ๋”ฉ์„ ์‘์šฉํ•œ CSS ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง, ๊ทธ๋ฆฌ๊ณ  ์ค‘์ฒฉ CSS


Blazor์—์„œ ๋ฐ”์ธ๋”ฉ๊ณผ CSS๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์กฐ๊ฑด๋ถ€๋กœ HTML ์š”์†Œ๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ์Šคํƒ€์ผ์„ ์œ ์—ฐํ•˜๊ฒŒ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ ์ด๋ฏธ ์ •์˜๋œ ์Šคํƒ€์ผ์ด ์กด์žฌํ•˜๋”๋ผ๋„ ์ค‘์ฒฉํ•ด์„œ ์ด๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

HTML

<div class="comment @(comment.IsEditMode ? "block" : "")">
    ...
</div>

์œ„์™€ ๊ฐ™์ด ๋ฐ”์ธ๋”ฉ์„ ํ†ตํ•œ ์กฐ๊ฑด๋ถ€ ๋ Œ๋”๋ง, ๊ทธ๋ฆฌ๊ณ  ์Šคํƒ€์ผ์„ ์ค‘์ฒฉ์‹œ์ผœ ๋”์šฑ ํ’๋ถ€ํ•˜๊ณ  ์œ ์—ฐํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง‘๋‹ˆ๋‹ค.

CSS

.comment {
    ...
    display: none;
}


.block {
    display: block;
}

Blazor์˜ ๊ฒฉ๋ฆฌ๋œ CSS ๊ตฌ์กฐ๋ฅผ ํ†ตํ•ด ์ค‘์ฒฉ ์Šคํƒ€์ผ ํ™œ์šฉ์ด ์•„์ฃผ ์žฌ๋ฐŒ๋„ค์š”, ์—ฌ๋Ÿฌ๋ถ„๋„ ๋‹ค์–‘ํ•˜๊ฒŒ ํ™œ์šฉํ•ด๋ณด๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

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