[WPF] ContentPresenter๋ž€?

WPF์˜ ํฐ ์žฅ์ ์ด XAML์„ ์ด์šฉํ•˜์—ฌ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„์ด ์œ ์—ฐํ•œ Windows Desktop App ๊ฐœ๋ฐœ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ธ๋ฐ์š”, ์ด ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„์ด ์œ ์—ฐํ•œ ๋ ˆ๋ฒจ์ด ๋˜๋ ค๋ฉด XAML์˜ ๋Ÿฌ๋‹์ปค๋ธŒ๊ฐ€ ์ข€ ์žˆ๋Š” ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์ด์ œ ๊ฐ“ WPF๋ฅผ 1๋…„ ๋‚จ์ง“ ํ•œ ์ €๋กœ์„œ๋Š” ContentPresenter๋Š” ์ข€ ์–ด๋ ค์šด ๊ฐœ๋…์ธ๋ฐ์š”.

WPF์˜ ์ปจํŠธ๋กค์€ ๋ฌด์กฐ๊ฑด ContentControl, ItemsControl๋ฅผ ์ƒ์†๋ฐ›์•„ ๊ตฌํ˜„๋˜์—ˆ๋‹ค๊ณ  ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.
ContentControl์€ ํ•˜์œ„ ์ปจํŠธ๋กค์„ ๋”ฑ 1๊ฐœ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ์ปจํŠธ๋กค์ด๊ณ , ItemsControl์€ ํ•˜์œ„ ์ปจํŠธ๋กค๋กœ Collectionํ˜•ํƒœ์˜ ๋‹ค์ˆ˜์˜ Item์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ์œผ๋ฉฐ, ์ด ๋•Œ ํ•˜์œ„ ์ปจํŠธ๋กค์— ๋Œ€ํ•œ ํ‘œํ˜„ ํ˜•์‹์„ DataTemplate์œผ๋กœ ์—ฌ๋Ÿฌ Control๋“ค์„ ์กฐํ•ฉํ•˜์—ฌ ํ‘œํ˜„ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์ €๊ฐ™์€ ์ดˆ๋ณด๋“ค์ด ์ด๋Ÿฐ ๊ถ๊ธˆ์ฆ์„ ๊ฐ–๋Š” ๋“ฏ ํ•ฉ๋‹ˆ๋‹ค. DataTemplete์œผ๋กœ ์ปจํŠธ๋กค๋“ค์„ ์กฐํ•ฉํ•˜์—ฌ ์ž์œ ๋กญ๊ฒŒ ํ‘œํ˜„์ด ๊ฐ€๋Šฅํ•œ๋ฐ ๋„๋Œ€์ฒด ControlTemplate์€ ์–ธ์ œ์“ฐ๋Š”๊ฑฐ์ง€? ์‹ค์ œ๋กœ ์ €๊ฐ™์€ ์ดˆ๋ณด๋ฅผ ๋งŽ์ด๋ณด์ง€๋งŒ ์ €๋„ ๋ชฐ๋ผ์„œ ๋‹ต๋ณ€์„ ๋ชปํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์ฐพ์•„๋ณด๋‹ˆ Winform์—์„œ OnPaint๊ฐ™์€ ๋ฉ”์„œ๋“œ๋กœ ์ปจํŠธ๋กค์„ ๋‹ค์‹œ ๊ทธ๋ฆฌ๋“ฏ, ์ปจํŠธ๋กค์˜ ์›ํ˜•์„ ๋ญ‰๊ฐœ๋ฒ„๋ฆฌ๊ณ  ์™„์ „ํžˆ ์ƒˆ๋กœ์šด ํ˜•ํƒœ์˜ ์‹œ๊ฐ์  ์ปจํŠธ๋กค๋กœ ํƒˆ๋ฐ”๊ฟˆ ์‹œํ‚ฌ ๋•Œ ControlTemplate์„ ์“ฐ๋Š” ๊ฒƒ ๊ฐ™์•˜์Šต๋‹ˆ๋‹ค. ๊ทธ๋ž˜์„œ ์•„์ง ์ดˆ๋ณด์ˆ˜์ค€์ด๋ผ ์ปจํŠธ๋กค์˜ ํ˜•ํƒœ๋ฅผ ๋ฐ”๊ฟ” ๋ฒ„๋ฆด ๋งŒํผ์˜ ์‹œ๊ฐ์  ์—…๋ฌด๋Š” ๋ชปํ•˜๋Š”๋ฐ๋‹ค ์‚ฐ์—…์šฉ ํ”„๋กœ๊ทธ๋žจ์ด๋‹ค๋ณด๋‹ˆ ๊ทธ๋ƒฅ ์ด๋Ÿฐ๊ฑฐ๋‹ค๋งŒ ํ•˜๊ณ  ๋„˜์–ด๊ฐ”๋Š”๋ฐ์š”.

DevExpress๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์˜ˆ์ œ๋กœ ๋ฐ›์€ ์ƒ˜ํ”Œ์ด ๊ฐ„๋‹จํ•˜๊ฒŒ ๋นจ๊ฐ„ ํ…Œ๋‘๋ฆฌ๋งŒ ์น˜๋Š” ๊ฒƒ์ธ๋ฐ ControlTemplate์„ ์‚ฌ์šฉํ•ด์„œ ์ •์˜๋ฅผ ํ•˜๊ณ , ContentPresenter๋ฅผ ์“ฐ๊ณ  ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. ContentPresenter๋ผ๋Š” ๊ฒƒ์„ ์ฒ˜์Œ ๋ณธ ๊ฒƒ์€ ์•„๋‹ˆ์ง€๋งŒ, ์ดํ•ดํ•˜๊ธฐ ์–ด๋ ค์›Œ์„œ ์ผ๋‹จ ๋„˜์–ด๊ฐ€๊ณ  ์žˆ์—ˆ๋Š”๋ฐ, ๋ง‰์ƒ ์˜ˆ์ œ๋กœ ๋ฐ›์•„๋ณด๋‹ˆ ์ด์ œ๋Š” ์•Œ์•„์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์–ด์„œ ์ด๊ฒƒ์ €๊ฒƒ ์ž๋ฃŒ์กฐ์‚ฌ๋ฅผ ํ•ด๋ดค์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์•„์ง ์ดํ•ด๊ฐ€ ์ข€ ํž˜๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๋Ÿฌ ์˜ˆ์ œ๋“ค์„ ๋ณด๋‹ˆ ๋ณธ ์˜ˆ์ œ์ค‘์—์„œ๋Š” ControlTemplate์€ ContentPresenter๋ž‘ 1:1๋กœ ๊ผญ ๋ถ™์–ด ๋‹ค๋‹ˆ๋ฉด์„œ ControlTemplate์„ ์‚ฌ์šฉํ•ด์„œ ์žฌ์ •์˜ํ•œ ๊ฒƒ์„ ๊ทธ๋ƒฅ <ContentPresenter /> ์ด๊ฑฐ ํ•œ ์ค„๋กœ ํ‘œํ˜„ํ•ด์ฃผ๋Š” ๋Š๋‚Œ์ด์—ˆ์Šต๋‹ˆ๋‹ค. ์‚ฌ์šฉ๋ฒ•์ด ์ข€ ์ดํ•ด๊ฐ€ ์•ˆ ๊ฐ”๋˜๊ฒŒโ€ฆ์žฌ์ •์˜ํ•œ XAML์˜ ๊ฐ€์žฅ ์•ˆ์ชฝ์— <ContentPresenter/>์ด๊ฑฐ๋งŒ ์“ฐ๋Š”๊ฑฐ ๊ฐ™๋˜๋ฐ XAML์˜ ์–ด๋Š๋ถ€๋ถ„์—์„œ ์ € ์ฝ”๋“œ๋ฅผ ์จ์•ผํ•˜๋Š”์ง€๋„ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค.

ํ˜น์‹œ ControlTemplate๊ณผ ContentPresenter์— ๋Œ€ํ•ด ์ด๊ฑฐ๋‹ค! ๋ผ๊ณ  ์„ค๋ช…์ด ๊ฐ€๋Šฅํ•œ ์•„ํ‹ฐํด์ด ์žˆ์„๊นŒ์š”? ์žˆ์œผ๋ฉด ๋งํฌ ๋ถ€ํƒ๋“œ๋ฆฌ๊ณ โ€ฆ์„ค๋ช…๋„ ๋ถ€๊ฐ€์ ์œผ๋กœ ํ•ด์ฃผ์‹ ๋‹ค๋ฉด ๊ฐ์‚ฌ๋“œ๋ฆฌ๊ฒ ์Šต๋‹ˆ๋‹ค.

์ข‹์•„์š” 1

DataTemplete๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ• ๊ฒƒ์ด๋ƒ ์ด๊ณ , ControlTemplete๋Š” ์ปจํŠธ๋กค์„ ์–ด๋–ป๊ฒŒ ํ‘œํ˜„ํ• ๊ฒƒ์ด๋ƒ์˜ ์ฐจ์ด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ž์‹ ์ด ์ง์ ‘ ์ปจํŠธ๋กค์„ ๋งŒ๋“ค๊ฑฐ๋‚˜, ์•„๋‹ˆ๋ฉด ๊ธฐ์กด์˜ ์ปจํŠธ๋กค์˜ ๋ชจ์–‘์„ ์ˆ˜์ •ํ•˜์ง€ ์•Š์œผ๋ฉด ControlTemplete๋Š” ์‹ค์ œ๋กœ ์‹ค๋ฌด์— ๊ทธ๋‹ฅ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค. (๊ธฐ์กด์˜ ์ปจํŠธ๋กค์„ ์ž˜ ์ด์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.)

ControlTemplete์˜ ํ›Œ๋ฅญํ•œ ์˜ˆ์ œ๋Š” WPF์—์„œ ๊ธฐ๋ณธ ์ œ๊ณตํ•˜๋Š” ์ปจํŠธ๋กค๋“ค์˜ ์†Œ์Šค์ฝ”๋“œ์ž…๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” TextBox, Label, Button ๋“ฑ์€ ๋‚ด๋ถ€์ ์œผ๋กœ ControlTemplete์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋ณด์—ฌ์ง€๋Š”์ง€๋ฅผ Style๋กœ ๊ธฐ๋ณธ ์ง€์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ModernWpfUI ๋“ฑ์˜ WPF UI ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ธฐ๋ณธ ์ปจํŠธ๋กค ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ž์ฒด ์ œ๊ณตํ•˜๋Š” ์ปจํŠธ๋กค์˜ ControlTemplete๋ฅผ ๋ฐ˜๋“œ์‹œ ์ง€์ •ํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

ContentPresenter๋Š” ๊ฐ„๋‹จํžˆ ์ ‘๊ทผํ•˜์…”๋„ ๋˜์„ธ์š”. ์™ธ๋ถ€์˜ Content๊ฐ€ ๊ทธ ์ž๋ฆฌ์— ๋†“์—ฌ์ง„๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ์˜ˆ๊ฐ€ Button์˜ Content์ธ๋ฐ, MS ๋ฌธ์„œ์˜ ์˜ˆ์ œ ์ฝ”๋“œ๋ฅผ ์ž ์‹œ ๋นŒ๋ ค์˜ค๊ฒ ์Šต๋‹ˆ๋‹ค.

<Style TargetType="Button">
  <!--Set to true to not get any properties from the themes.-->
  <Setter Property="OverridesDefaultStyle" Value="True"/>
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="Button">
        <Grid>
          <Ellipse Fill="{TemplateBinding Background}"/>
          <ContentPresenter HorizontalAlignment="Center"
                            VerticalAlignment="Center"/>
        </Grid>
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

TargetType์„ ๊ธฐ๋ณธ ํƒ€์ž…์ธ Button์œผ๋กœ ์ง€์ •ํ–ˆ์œผ๋ฏ€๋กœ ์ ์šฉ๋˜๋Š” ๋ฆฌ์†Œ์Šค์˜ ์œ„์น˜(๋‹จ๊ณ„)์— ๋”ฐ๋ผ ๊ทธ ๋‹จ๊ณ„ ์ดํ›„์—” ์ „์—ญ ์ ์šฉ์ด ๋˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

<Button>xxx</Button>

xxx์˜ ํŠธ๋ฆฌ๊ฐ€ ๊ทธ๋Œ€๋กœ ContentPresenter์˜ ์œ„์น˜์— ๋“ค์–ด๊ฐ„๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

Content๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์ธ ์ปจํŠธ๋กค๋„ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ๋‹ค์Œ ์ฒ˜๋Ÿผ ContentPresenter์— Content์†์„ฑ์— TempleteBinding ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

<ControlTemplate>  
    <Grid>
        <ContentPresenter Content="{TemplateBinding ContentLeft}" HorizontalAlignment="Left"/>
        <ContentPresenter Content="{TemplateBinding ContentRight}" HorizontalAlignment="Right"/>
    </Grid>
</ControlTemplate> 

์—ฌ๊ธฐ์„œ ContentLeft, ContentRight๋Š” ์ด ์ปจํŠธ๋กค์—์„œ ํ…œํ”Œ๋ฆฟ ๋ฐ”์ธ๋”ฉ ๋˜๋„๋ก ๋…ธ์ถœํ•ด์ค˜์•ผ ํ•ฉ๋‹ˆ๋‹ค.

์ข‹์•„์š” 4

WPF ์ปจํŠธ๋กค XAML์œ„์น˜๋Š” ์•„๋งˆ ์—ฌ๊ธฐ ์ผ๊บผ์—์š”.

wpf/src/Microsoft.DotNet.Wpf/src/Themes/XAML at main ยท dotnet/wpf (github.com)

์ข‹์•„์š” 2

@Vincent ๋‘์„œ ์—†์ด ์„ค๋ช…๋“œ๋ ค๋ณผ๊ฒŒ์š”.

์•„์‹œ๋Š” ๋ถ€๋ถ„๋„ ๋งŽ์œผ์‹œ๊ฒ ์ง€๋งŒ ์‹œ์ž‘ํ•˜์‹ค ๋ถ„๋“ค์„ ์œ„ํ•ด์„œ๋„ ์ƒ์„ธํ•˜๊ฒŒ ์„ค๋ช…๋“œ๋ฆฝ๋‹ˆ๋‹ค.

์šฐ์„  Control ํด๋ž˜์Šค์—์„œ๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด๋ณผ๊ฒŒ์š”.

Control ํด๋ž˜์Šค๋Š” Template (ControlTemplate) ์†์„ฑ์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

public class Control
{
    public ControlTemplate Template { get; set; }
}

๊ทธ๋ฆฌ๊ณ  ItemsControl๊ณผ ContentControl์€ Control ํด๋ž˜์Šค๋ฅผ ์ƒ์†๋ฐ›๊ณ  ์žˆ์ฃ . ๊ทธ๋ž˜์„œ ์ด ๋‘˜์€ Template์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์š”.

Template (ControlTemplate)์€ ์ปจํŠธ๋กค ๋ชจ์–‘์ด๋ผ๊ณ  ์ƒ๊ฐํ•˜๋ฉด ํŽธํ•ด์š”.

๊ทธ๋ฆฌ๊ณ ,
๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณต๋˜๋Š” Button์€ ์‹ค์ œ๋กœ ControlTemplate์ด ์•„๋ž˜์ฒ˜๋Ÿผ ๊ตฌํ˜„๋˜์–ด ์žˆ์„๊ฒ๋‹ˆ๋‹ค.

<Style TargetType="{x:Type Button}">
    <Setter Property="Template">
        <ControlTemplate TargetType="{x:Type Button}">
            <Border BorderThickness="1"
                    BorderBrush="#CCCCCC"
                    Background="{TemplateParent Background}"
                    Padding="8 4 8 4"
                    CornerRadius="2 2 2 2">
                <ContentPresenter ContentSource="Content"/>
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="#DDDDDD"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Setter>
</Style>

๋ฒ„ํŠผ์˜ ๋ชจ์–‘, ํŠธ๋ฆฌ๊ฑฐ ๋“ฑ์€ ControlTemplate์—์„œ ์ •์˜ํ•˜๊ณ , ๋‚ด๋ถ€์— ๋” ์ปค์Šคํ„ฐ๋งˆ์ด์ง• ๊ฐ€๋Šฅํ•œ ์˜์—ญ์„ ์ง€์ •ํ•˜๊ธฐ ์œ„ํ•ด ContentPresenter๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๊ทธ๋ž˜์„œ Button์„ ์‚ฌ์šฉํ•  ๋•Œ์—๋Š” Content ๋‚ด์šฉ๋งŒ ๋„ฃ์œผ๋ฉด ๋˜์ฃ .

<Button Content="๋ฒ„ํŠผ"/>

Content๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ๋‚ด๋ถ€์ ์œผ๋กœ ContentPresenter๋ฅผ ๋Œ€์ฒดํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์ด์™€ ๋™์ผํ•œ ๊ฐœ๋…์œผ๋กœ Window ํด๋ž˜์Šค ๋˜ํ•œ ๋™์ผํ•œ ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค.
์œˆ๋„์šฐ๋„ ๋ฒ„ํŠผ๊ณผ ๋™์ผํ•˜๊ฒŒ ContentControl์„ ์ƒ์†๋ฐ›๋Š”๋ฐ์š”.

์ด๋ฏธ ์œˆ๋„์šฐ๋„ ControlTemplate์„ ์•„๋ž˜์ฒ˜๋Ÿผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

<Style TargetType="{x:Type Window}">
    <Setter Property="Template">
        <ControlTemplate TargetType="{x:Type Window}">
            <Border>
                <Grid>
                    <Grid.RowDefinition>
                        <RowDefinition Height="Auto"/>
                        <RowDefinition Height="*"/>
                    </Grid.RowDefinition>
                    <Button x:Name="PART_MinButton"/>
                    <Button x:Name="PART_MaxButton"/>
                    <Button x:Name="PART_CloseButton"/>
                    <ContentPresenter ContentSource="Content"/>
                </Grid>
            </Border>
        </ContentTemplate>
    </Setter>
</Style>

์œˆ๋„์šฐ ํด๋ž˜์Šค๋„ ์ด๋ฏธ ControlTemplate์—์„œ ๋ชจ๋“  ๋ชจ์–‘์ด ๊ตฌํ˜„๋˜์–ด ์ œ๊ณต๋˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ContentPresenter ์˜์—ญ์— ํ•ด๋‹นํ•˜๋Š” Content ๋ถ€๋ถ„๋งŒ ์ฑ„์›Œ ๋„ฃ์œผ๋ฉด ๋˜๋Š”๋ฐ์š”.

์†Œ์Šค์ฝ”๋“œ์—์„œ๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ Content ์˜์—ญ๋งŒ ์‚ฌ์šฉํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Button btn = new();
btn.Content "ํ™•์ธ";

Window win = new();
win.Content = new Grid();

๋˜ํ•œ ์ด๋ฏธ ControlTemplate์ด ์ •์˜๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—,
Xaml์—์„œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Content ์˜์—ญ๋งŒ ์‹ ๊ฒฝ์“ฐ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

<Window x:Class="Exam.MainWindow.cs" ...>
    <Window.Content>
        <Grid>
            <!-- ์œˆ๋„์šฐ ์•ˆ ์˜์—ญ -->
        </Grid>
    </Window.Content>
</Window>

ContentControl, ItemsControl์„ ์ƒ์†๋ฐ›๋Š” ๋ชจ๋“  ์ปจํŠธ๋กค์€ ์‚ฌ์‹ค ControlTemplate์˜ ๋ชจ์–‘(๊ธฐ๋ฐ˜)์„ ์‹œ์ž‘์œผ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ๋Š” ์…ˆ์ด์ฃ .

๊ทธ๋ฆฌ๊ณ  Content๋Š” ์ƒ๋žตํ•  ์ˆ˜ ๋„ ์žˆ์–ด์„œ ์šฐ๋ฆฌ๊ฐ€ Window๋‚˜ UserControl์„ ์ƒ์„ฑํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ๋ฐ”๋กœ Grid ๋“ฑ์˜ UI ์ปจํŠธ๋กค์„ ๋ฐฐ์น˜์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(์ด๋Ÿฐ ์ƒ๋žต ๊ทœ์น™์ด Content ๊ฐœ๋…์„ ์ดํ•ดํ•˜๋Š”๋ฐ ๋…์ด ๋˜์ง€ ์•Š์•˜๋‚˜ ์ƒ๊ฐํ•ด์š”โ€ฆ)

<Window x:Class="Exam.MainWindow.cs" ...>
    <Grid>
        <views:ProfileView/>
    </Grid>
</Window>
<Button>
    ํ™•์ธ
</Button>

๊ทธ๋ž˜์„œ ํ‰๋ฒ”ํ•ด ๋ณด์ด๋Š” Content ์†์„ฑ์ด WPF์—์„œ๋Š” ์‹ค๋กœ ์—„์ฒญ ์ค‘์š”ํ•œ ์—ญํ• ์„ ํ•˜๊ณ  ์žˆ์ฃ .

Control ์ž…์žฅ์—์„œ ๋ดค์„ ๋•Œ ControlTemplate๋Š” ํ•„์ˆ˜์ด๊ณ  ContentPresenter๋Š” ์„ ํƒ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค. ๋˜ ContentPresenter๋Š” ์–ผ๋งˆ๋“ ์ง€ ๊ฐœ์ˆ˜๋ฅผ ๋Š˜๋ฆด ์ˆ˜๋„ ์žˆ์–ด์š”.

๊ฐ€๋ น Expander๋Š” 2๊ฐœ์˜ ContentPresenter๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ฃ .

<Style TargetType="{x:Type TabItem}">
    <Setter Property="Template">
        <ControlTemplate TargetType="{x:Type TabItem}">
            <StackPanel>
                <ContentPresenter ContentSource="Header"/>
                <ContentPresenter ContentSource="Content"/>
            </StackPanel>
        </ContentTemplate>
    </Setter>
</Style>

๋•Œ๋ฌธ์— ContentPresenter๋ฅผ ์•„๋ž˜์ฒ˜๋Ÿผ ๋‹ค์–‘ํ•˜๊ฒŒ ์ด๋ฅผ ๋‹ค์–‘ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<Expander Header="์ ‘๊ธฐ">
    <!-- ๋‚ด์šฉ -->
</Expander>

<Expander Header="์ ‘๊ธฐ" Content="๋‚ด์šฉ"/>

<Expander>
    <Expander.Header>
        <CheckBox Content="์ ‘๊ธฐ"/>
    </Expander.Header>
    <Expander.Content>
        <DataGrid/>
    </Expander.Content>
</Expander>

<Expander HeaderTemplate="{StaticResource MyHeaderStyle}"/>
    <DataGrid/>
</Expander>

์ด์ฒ˜๋Ÿผ Expander ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Window, UserControl, GroupBox, TabControl, TabItem, ComboBox ๋“ฑ๋“ฑ ๋‹ค์–‘ํ•œ ์ปจํŠธ๋กค์„ ControlTemplate ์„ ํ†ตํ•ด ์„ค๊ณ„ํ•˜๊ณ  ContentPresenter ๋˜๋Š” ItemsPresenter ์˜์—ญ์„ ํ™œ์šฉํ•ด์„œ ๊ฐ€๋ณ€์ ์ธ UI๋ฅผ ๋งŒ๋“ค๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

๋์œผ๋กœโ€ฆ

ControlTemplate์„ ์ž˜ ํ™œ์šฉํ•œ๋‹ค๋ฉด DevExpress ๊ฐ™์€ ์ปจํŠธ๋กค์„ ์›ํ•˜๋Š” ๋ฐฉํ–ฅ์œผ๋กœ ์ง์ ‘ ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ œ ๊ฐœ์ธ์ ์œผ๋กœ๋Š” ์ด ๊ฐœ๋…์ด WPF์—์„œ๊ฐ€์žฅ ์ค‘์š”ํ•œ ๋‚ด์šฉ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ด์š”.

๊ทธ๋ฆฌ๊ณ  ControlTemplate์— ์ต์ˆ™ํ•ด์ง„๋‹ค๋ฉด ๋ญ๋“  ๋‹ค ๋งŒ๋“ค ์ˆ˜ ์žˆ๊ณ ์š”. :smile:

์ฝ์–ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

์ข‹์•„์š” 6

๋‹จ๊ณ„์ ์œผ๋กœ ์„ค๋ช… ์ž˜ ์ฃผ์…”์„œ ๊ด€๋ จ ํ•„์š”ํ•œ ๋ชจ๋“  ๋ถ„๋“ค์—๊ฒŒ ์œ ์ตํ•œ ๊ธ€์ธ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค :slight_smile:

์ข‹์•„์š” 2

์Œโ€ฆ ์˜ˆ์ „์— WPF์— ๋Œ€ํ•ด์„œ ํšŒ์‚ฌ ์ดˆ์งœ๋“ค ๊ต์œกํ• ๋•Œ ์ข€ ํ–ˆ์—ˆ๋Š”๋ฐโ€ฆ
๋งŽ์€ ๋ถ„๋“ค์ด ๋‹ต์„ ๋‹ฌ์•„์ฃผ์…จ์ง€๋งŒ, ์ œ๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ์ ‘๊ทผ๋ฒ•๋„ ์ดํ•ดํ•˜์‹œ๋Š”๋ฐ์— ๋„์›€์ด ๋˜์‹ค๊ฑฐ ๊ฐ™์•„์š”!
(์ด์ œ ๊ทธ ์ดˆ์งœ๋“ค์ด ์•Œ์•„์„œ ์ข€ ํ•ด์„œ ์ œ๊ฐ€ UI๋ฅผ ์•ˆ๋งŒ์ง€๋‹ค ๋ณด๋‹ˆ ๊ธฐ์–ต์ด ์ž˜ ๋‚˜์ง„ ์•Š์ง€๋งŒโ€ฆ)

์ด๊ฑฐ ์‚ฌ์‹ค ์ฒ˜์Œ ํ•˜์‹œ๋Š” ๋ถ„๋“ค์€ ์ง„์งœ ๋ณต์žกํ•˜์ฃ โ€ฆ
ํ•˜์ง€๋งŒ ์ดํ•ดํ•˜๋ฉด MS์˜ ์–ด๋งˆ์–ด๋งˆํ•œ ์•„ํ‚คํ…์ฒ˜๋ง์„ ํ๋Š๋‚„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ์„  ์ œ๊ฐ€ ๋‹ตํ•˜๊ณ ์ž ํ•˜๋Š” ์งˆ๋ฌธ์€ ์•„๋ž˜ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

ControlTemplate๊ณผ ContentPresenter์— ๋Œ€ํ•ด ์ด๊ฑฐ๋‹ค!

0, ์‚ฌ์ „ ์ง€์‹
MS๋Š” UI Control์—์„œ Logic๊ณผ Visual ์„ ์™„๋ฒฝํ•˜๊ฒŒ ๋ถ„๋ฆฌํ•˜๊ณ  ์‹ถ์—ˆ์Šต๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ๊ทธ๊ฒƒ์„ ์ฒ˜์Œ์œผ๋กœ ๋„์ž…ํ•œ๊ฒƒ์ด WPF์ž…๋‹ˆ๋‹ค.
๋ฐ”๋กœ FrameworkElement์™€ FrameworkTemplate์ž…๋‹ˆ๋‹ค.

  • FrameworkElement : UI Logic ๋‹ด๋‹น (์ด๋ฅผ ์œ„ํ•œ ๋งˆ์šฐ์Šค ์ด๋ฒคํŠธ ๋ฐ UI๋กœ์จ ์‚ฌ์šฉ์ž์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š”๋ฐ์— ํ•„์š”ํ•œ ๊ฒƒ๋“ค์˜ ์ฑ…์ž„์„ ๊ฐ€์ง‘๋‹ˆ๋‹ค.)
  • FrameworkTemplate : Visual ๋‹ด๋‹น (์ฐ์–ด๋‚ผ ์ˆ˜ ์žˆ๋Š” Visual์˜ ๋ชจ์Šต์„ ๋‹ด์Šต๋‹ˆ๋‹ค.)

์ด๋ ‡๊ฒŒ ๋ถ„๋ฆฌ๋œ 2๊ฐœ๊ฐ€ ์–ด๋””์„œ ๋งŒ๋‚˜๋ƒ๋ฉดโ€ฆ
๋ฐ”๋กœ Control์ž…๋‹ˆ๋‹ค.

์ฆ‰, ์ด์ œ ์šฐ๋ฆฌ๋Š” MS์˜ ๋งˆ๋ฒ•(?)์— ์˜ํ•ด ๋กœ์ง์„ ๊ทธ๋Œ€๋กœ ์žฌ์‚ฌ์šฉํ•˜๋ฉด์„œ Visual๋งŒ ๋ฐ”๊ฟ€ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Visual๊ณผ ์ƒํ˜ธ์ž‘์šฉ์„ ์œ„ํ•œ Logic์˜ ๋ถ„๋ฆฌ.

์œ„ ๋ฌธ์žฅ์„ ๊ผญ ๊ธฐ์–ตํ•˜์„ธ์š”!
๊ทธ๋ž˜์•ผ์ง€ WPF์˜ ์ปจํŠธ๋กค ์ŠคํŠธ๋Ÿญ์ฒ˜๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1. ContentPresenter
ContentPresenter๋Š” Content๋ผ๋Š” ๊ทธ ํŠน์ •(?)์˜ ๋ฌด์–ธ๊ฐ€๋ฅผ ํ‘œ์‹œ ํ•˜๋Š”๋ฐ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋Ÿผ ์—ฌ๊ธฐ์„œ ์ด Content๋ž€ ๋ฌด์—‡์ผ๊นŒ์š”?

๋ฌด์—‡์ด๋“  ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๊ฐ€ ์ฝ”๋“œ๋ ˆ๋ฒจ์—์„œ ์ž‘์„ฑํ•˜๋Š” ๋ชจ๋“  ์ฝ”๋“œ์— Visual์„ ์”Œ์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์•„๋ž˜์™€ ๊ฐ™์€ ๊ฐœ์ฒด๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

class Person
{
   public string Name { get; set; }
}

์ด๊ฒƒ์€ ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ์˜ ๋‹จ์ˆœ Class์ž…๋‹ˆ๋‹ค.
์ด๊ฒƒ์€ ์ผ๋ฐ˜์ธ๋„ ์ธ์‹ํ•  ์ˆ˜ ์žˆ๋Š” Graphic์œผ๋กœ ํ‘œํ˜„๋œ Visual ์ด ์—†์Šต๋‹ˆ๋‹ค.

์ด๋Ÿฌํ•œ ๋†ˆ๋“ค์—๊ฒŒ Visual์„ ์ž…ํ˜€์„œ ํ‘œํ˜„ํ•˜๋Š”๊ฒƒ, ๊ทธ๊ฒƒ์ด ContentPresenter์ž…๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  Visual์„ ์ •์˜ํ•˜๋Š”๊ฒƒ์ด DataTemplate(FrameworkTemplate์„ ์ƒ์†)์ž…๋‹ˆ๋‹ค.

<ContentPresenter Content="{binding person}" ContentTemplate="{StaticResource Person.DefaultVisual}">

// (๋ฌธ๋ฒ• ์ด๊ฑฐ ๋งž๋‚˜์š”? ์˜ค๋žœ๋งŒ์ด๋ผ;;;)

์œ„ ๊ตฌ๋ฌธ์„ ์ด๋ ‡๊ฒŒ ํ•ด์„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ๋งŒ ์กด์žฌํ•˜๋Š” Person์ด๋ผ๋Š” ๊ฐœ์ฒด๋ฅผ Person.DefaultVisual์˜ ๋ชจ์Šต์œผ๋กœ Visual์„ ์ž…ํ˜”๋‹ค.

๊ทธ๋ฆฌ๊ณ  ์—ฌ๊ธฐ์„œ๋„ MS๊ฐ€ ์ด๋ฃจ๊ณ ์ž ํ–ˆ๋˜ Logic ๊ณผ Visual์˜ ๋ถ„๋ฆฌ๋ฅผ ์ด๋ฃจ์–ด๋‚ธ๊ฒƒ์ž…๋‹ˆ๋‹คโ€ฆ

์ดํ•ด๋ฅผ ๋•๊ธฐ ์œ„ํ•ด class๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ, ์–ธ๊ธ‰ํ–ˆ๋“ฏ Content๋Š” ๋ฌด์—‡์ด๋“  ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค. ์‹ฌ์ง€์–ด enum์ด๋ผ๋„ ์ƒ๊ด€์—†์Šต๋‹ˆ๋‹ค. ์ค‘์š”ํ•œ๊ฑด Code level์—์„œ๋งŒ ์กด์žฌํ•˜๋Š” ๊ฒƒ์— Visual(Graphic)์„ ์ž…ํžˆ๋Š”๊ฒƒ ์ž…๋‹ˆ๋‹ค.

๋‹ค์‹œ ํ•œ๋ฒˆ ํ•œ๋งˆ๋””๋กœ ์ •๋ฆฌํ•˜์ž๋ฉด, ContentPresenter๋Š” ๋ฌด์—‡์ด๋“  ์ƒ๊ด€์—†๋Š” ๊ทธ Content๋ผ๋Š” ๋†ˆ์„ ์œ„ํ•œ ํ‘œ์‹œ๊ธฐ!

2. ControlTemplate

ControlTemplate์€ ์‚ฌ์‹ค ์‰ฝ์Šต๋‹ˆ๋‹ค.
ํ•œ๋งˆ๋””๋กœ ์ด์•ผ๊ธฐํ•˜์ž๋ฉด Control ํด๋ž˜์Šค๋ฅผ ์œ„ํ•œ ์ „์šฉ FrameworkTemplate์ž…๋‹ˆ๋‹ค

FrameworkTemplate์€ ์ถ”์ƒํ™”์ž…๋‹ˆ๋‹ค.
๊ตฌํ˜„์ฒด๋กœ ๋‘๊ฐ€์ง€๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ๊ทธ๊ฒƒ์€ ControlTemplate๊ณผ DataTemplate์ž…๋‹ˆ๋‹ค.

๊ฐ๊ฐ ์šฉ๋„๋Š” ์•„๋ž˜์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ControlTemplate
    Control ํด๋ž˜์Šค ์ „์šฉ Visual ๋‹ด๋‹น.
    ์ฆ‰, UI Control๋กœ์จ ์‚ฌ์šฉ์ž์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” Logic์„ ์œ„ํ•œ Visual์„ ์ •์˜ ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

  • DataTemplate
    ContentPresenter ํด๋ž˜์Šค์˜ ์ „์šฉ Visual ๋‹ด๋‹น
    ์ฆ‰, ๋ฌด์—‡์ด๋“  ์ƒ๊ด€์—†๋Š” ๊ทธ Content ๋ผ๋Š” ๋†ˆ์„ ์œ„ํ•œ Visual์„ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

๋‹ค์‹œ ํ•œ๋ฒˆ ํ•œ๋งˆ๋””๋กœ ์ •๋ฆฌํ•˜์ž๋ฉด, ControlTemplate์€ Control์„ ์œ„ํ•œ ์ „์šฉ Visual ๋‹ด๋‹น!


๋

์—ฌ๋‹ด์œผ๋กœโ€ฆ ์‚ฌ์‹ค ์ด๋Ÿฌํ•œ Logic๊ณผ View์˜ ๋ถ„๋ฆฌ๊ฐ€ ์žˆ์—ˆ๊ธฐ์—, MVVM์ด๋ผ๋Š” ํŒจํ„ด์ด ๋‚˜์˜ฌ ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
์ด ๋ง์„ ๋‹ค๋ฅธ๋ง๋กœ ํ’€์ž๋ฉดโ€ฆ MVVM์€ Framework์˜ ์ „ํญ์ ์ธ ์ง€์›์ด ์ค‘์š”ํ•œ ์š”์†Œ์ž…๋‹ˆ๋‹ค.
ํ•ด์„œโ€ฆ android์™€ ๊ฐ™์€๊ณณ์—์„œ์˜ MVVM์€ โ€ฆ ๋„ˆ๋ฌด ๋ณ„๋กœ์ž…๋‹ˆ๋‹คโ€ฆ

์ข‹์•„์š” 5

xxx์˜ ํŠธ๋ฆฌ๊ฐ€ ๊ทธ๋Œ€๋กœ ContentPresenter์˜ ์œ„์น˜์— ๋“ค์–ด๊ฐ„๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
Content๊ฐ€ ์—ฌ๋Ÿฌ๊ฐœ์ธ ์ปจํŠธ๋กค๋„ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฐ ๊ฒฝ์šฐ ๋‹ค์Œ ์ฒ˜๋Ÿผ ContentPresenter์— Content์†์„ฑ์— TempleteBinding ํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

์ด ์„ค๋ช…์ด ๋”ฑ ๊ฝ‚ํžˆ๋„ค์š” ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ใ…Žใ…Ž ํ…œํ”Œ๋ฆฟ ๋ฐ”์ธ๋”ฉ์€ ์ด๊ฒƒ๋งŒ๋ด์„œ๋Š” ์•„์ง ์ž˜ ๋ชจ๋ฅด๊ฒ ๋Š”๋ฐ ์ด๋ ‡๊ฒŒ ๊ณ ๊ธ‰์ง„ ๋‹ต๋ณ€์ด ์˜ฌ๋ผ์˜ฌ ๊ฑธ ์˜ˆ์ƒํ•˜์—ฌ ๋‹ค์Œ์— ํƒฌํ”Œ๋ฆฟ ๋ฐ”์ธ๋”ฉ๋„ ์งˆ๋ฌธ์„ ํ•œ ๋ฒˆ ์˜ฌ๋ ค๋ด์•ผ๊ฒ ์Šต๋‹ˆ๋‹ค ใ…Žใ…Ž

์ข‹์•„์š” 2

์™€ ๋„ˆ๋ฌด๋‚˜ ์ •์„ฑ์Šค๋Ÿฝ๊ณ  ๊ธธ๊ฒŒ ์ž˜ ์จ์ฃผ์…”์„œ ๋„ˆ๋ฌด๋‚˜ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ใ…Žใ…Ž

(์ด๋Ÿฐ ์ƒ๋žต ๊ทœ์น™์ด Content ๊ฐœ๋…์„ ์ดํ•ดํ•˜๋Š”๋ฐ ๋…์ด ๋˜์ง€ ์•Š์•˜๋‚˜ ์ƒ๊ฐํ•ด์š”โ€ฆ)

์ด ๋ถ„์ด ์–ด๋–ค ๋ง์ธ์ง€ ์•Œ๊ฒ ์Šต๋‹ˆ๋‹คโ€ฆใ…Žใ…Ž ์š”์ปจ๋Œ€ ControlTemplate์œผ๋กœ ๋‚ด๊ฐ€ ์–ด๋Š์ •๋„ ์ •์˜ํ•ด์ค„ํ…Œ๋‹ˆ ContentPresenter ๋ถ€ํ„ฐ๋Š” ๋„ค๊ฐ€ ์•Œ์•„์„œ ์ •์˜ํ•˜๋ ด ์š”๋Ÿฐ ๋Š๋‚Œ์ด๊ตฐ์š” ใ…Žใ…Ž ๋‹จ์ง€ Content์ž๋ฆฌ๋ฅผ ์ƒ๋žตํ•ด๋ฒ„๋ ค์„œ ๊ฑฐ๊ธฐ์— ์‚ฌ์‹ค ํ”„๋ ˆ์  ํ„ฐ๊ฐ€ ์˜ค๋Š”์ง€ ๋ชฐ๋ž๋˜ ์ ์ด ์•„์‰ฝ๋„ค์š” ใ…Žใ…Ž

๋‹ค์‹œ ํ•œ ๋ฒˆ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค!!

์ข‹์•„์š” 2

์˜ค์˜ค FrameworkElement์™€ FrameworkTemplate์— ๋Œ€ํ•œ ๊ฐœ๋…์€ ๋˜ ์ฒ˜์Œ ์ ‘ํ•ด๋ณด๋„ค์š”โ€ฆ ๋‚ด์ผ ์„ค๋ช…ํ•˜์‹ค ๋ถ€๋ถ„๋„ ๊ธฐ๋Œ€ํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค ใ…Žใ…Ž ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!

์ข‹์•„์š” 1

์•„ ControlTemplate๊ณผ DataTemplate ์ •์˜ ๋ถ€๋ถ„์ด ์ธ์ƒ์ ์ด๋„ค์š”. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ใ…Žใ…Ž

์ข‹์•„์š” 2

WPF ์“ฐ๋ฉด์„œ ๊ทธ๋™์•ˆ ๊ถ๊ธˆํ–ˆ๋˜ ์ ์ด ์‹œ์›ํ•˜๊ฒŒ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค : )

์ข‹์•„์š” 2

์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!
wpfํ•˜๋ฉด์„œ ๊ถ๊ธˆํ–ˆ๋˜์ ์ด ํ•ด์†Œ๋˜๋Š”๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค!

์ข‹์•„์š” 1