WPF Button ์—ฐ๊ตฌ

WPF์—์„œ ๊ฐ€์žฅ ๋งŽ์ด ์‚ฌ์šฉ๋˜๋Š” ์ปจํŠธ๋กค ์ค‘์— ํ•˜๋‚˜์ธ Button์— ๊ด€ํ•œ ์—ฐ๊ตฌ๋ฅผ ์ง„ํ–‰ํ•ฉ๋‹ˆ๋‹ค.

์—ฐ๊ตฌ ํ•ญ๋ชฉ

  1. ๋ฒ„ํŠผ(Button) ์‚ฌ๋ก€
  2. Button Class
  3. Template
  4. Geometry
  5. Trigger
  6. DataContext
  7. DependencyProperty

๋ชฉํ‘œ: (์†๋„๋Š” ๋”๋””์ง€๋งŒ) ์„ค๋ช…๊ณผ ์†Œ์Šค์ฝ”๋“œ๋ฅผ ์ƒ์„ธํ•˜๊ฒŒ ์ •๋ฆฌํ•˜๊ณ  WPF Button ๊ด€๋ จ ์ •๋ณด๋“ค์„ ์ž˜ ๊ฒ€์ฆ๊ณ  ์ง€์†์ ์œผ๋กœ ๊ด€๋ฆฌํ•ด ๋‚˜๊ฐ€๋Š” ๊ฒƒ์— ๋ชฉ์ ์„ ๋‘๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. :smile:

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

๋‹ค์–‘ํ•œ ํ”„๋กœ๊ทธ๋žจ์—์„œ์˜ ๋ฒ„ํŠผ(Button)

GitHub Repository ์ƒ์„ฑ ๋ฒ„ํŠผ

image

๋‹ท๋„ท๋ฐ๋ธŒ ํ† ํ”ฝ ๋งŒ๋“ค๊ธฐ ๋ฒ„ํŠผ

image

์นด์นด์˜คํ†ก ์ฑ„ํŒ…์ฐฝ ์ „์†ก ๋ฒ„ํŠผ

image

๋ฆฌ๊ทธ์˜ค๋ธŒ๋ ˆ์ „๋“œ ์•ˆ๋‚ด ๊ฐ€์ด๋“œ ๋ฒ„ํŠผ

image

Button Class (๋ฒ„ํŠผ ํด๋ž˜์Šค)

์ด๋ฆ„ UI ํƒ€์ž… ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์–ด์…ˆ๋ธ”๋ฆฌ
Button ContentControl System.Windows.Controls PresentationFramework.dll

WPF ๋ฒ„ํŠผ์€ Content ์†์„ฑ์„ ํฌํ•จํ•˜๋Š” ContentControl ๊ธฐ๋ฐ˜์˜ ํด๋ž˜์Šค์ž…๋‹ˆ๋‹ค. ContentControl์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๋Š” ํด๋ž˜์Šค๋Š” Button ๋ง๊ณ ๋„ Window, UserControl, CheckBox, ToggleButton, Expander ๋“ฑ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

Button ํด๋ž˜์Šค์˜ ๊ฐ€์žฅ ํฐ ํŠน์ง•์€ ContentTemplate์„ ํŽธ์ง‘ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ๊ณผ Click ์ด๋ฒคํŠธ๋ฅผ ํฌํ•จํ•œ Button ๋™์ž‘์— ๊ด€๋ จ๋œ Event๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค. ๋˜ํ•œ ๋‹ค๋ฅธ UI ํด๋ž˜์Šค๋“ค๊ณผ ๋‹ฌ๋ฆฌ Command๋ผ๋Š” ICommand ํƒ€์ž…์˜ ์†์„ฑ(DependencyProperty)๋ฅผ ํ†ตํ•ด Click ์ด๋ฒคํŠธ๋ฅผ Binding์„ ํ†ตํ•ด ์—ฐ๊ฒฐํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” Button ๋‚ด๋ถ€์ ์œผ๋กœ ๋ฒ„ํŠผ ํด๋ฆญ ์‹œ Command๋ฅผ ?.Invoke() ํ•˜๋„๋ก ์„ค๊ณ„๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ์Šคํƒ€์ผ ํ˜•ํƒœ

<Style TargetType="{x:Type Button}">
    <Setter>
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Button}">
                <Border>
                   <!-- TBD... -->
                    <ContentPresenter/>
                </Border>
            </ControlTemplate>
       </Setter.Value>
   </Setter>
</Style>

Button๊ณผ ๊ฑฐ์˜(99%) ๋™์ผํ•œ DNA
ContentControl์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ๋ชจ๋“  ์ปจํŠธ๋กค์ด ๋Œ€์ƒ์ž…๋‹ˆ๋‹ค.

  • ToggleButton
  • CheckBox
  • RadioButton
  • Window
  • UserControl

TBDโ€ฆ

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

๋ฒ„ํŠผ Template ์˜ˆ์ œ

  • ๊นƒํ—ˆ๋ธŒ ๋ฒ„ํŠผ
  • ๋‹ท๋„ท๋ฐ๋ธŒ ๋ฒ„ํŠผ
  • ์นด์นด์˜คํ†ก ๋ฒ„ํŠผ
  • ๋ฆฌ๊ทธ์˜ค๋ธŒ๋ ˆ์ „๋“œ ๋ฒ„ํŠผ

๋‹ค์šด๋กœ๋“œ
:point_right: GitHub ์†Œ์Šค์ฝ”๋“œ

๊นƒํ—ˆ๋ธŒ ๋ฒ„ํŠผ

๊ธฐ๋ณธ ์ƒํƒœ (Default)

image

์ƒ‰์ƒ ํ‘œ (HEX)

image BorderBrush #2B9148
image Background #2EA44F
image Foreground #FFFFFF
image Fill #FFFFFF

image Background.IsMouseOver #2c974b

์•„์ด์ฝ˜ (Geometry)

<Geometry x:key="ICON">M8,8V6H10V8H8M7,2H17A2,2 0 0,1 19,4V19A2,2 0 0,1 17,21V22H15V21H9V22H7V21A2,2 0 0,1 5,19V4A2,2 0 0,1 7,2M7,4V9H17V4H7M8,12V15H10V12H8Z</Geometry>

์Šคํƒ€์ผ (ControlTemplate)

<!-- Geometry Path Icon (.SVG) -->
<Geometry x:Key="ICON">M8,8V6H10V8H...</Geometry>

<!-- GitHub Button Style -->
<Style TargetType="{x:Type local:GitHubButton}">
	<Setter Property="UseLayoutRounding" Value="True"/>
	<Setter Property="SnapsToDevicePixels" Value="True"/>
	<Setter Property="Foreground" Value="#FFFFFF"/>
	<Setter Property="FontWeight" Value="Bold"/>
	<Setter Property="Margin" Value="5"/>
	<Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type local:GitHubButton}">
				<ControlTemplate.Resources>
					<Style TargetType="{x:Type Border}" x:Key="IN.BORDER">
						<Setter Property="BorderBrush" Value="#2B9148"/>
						<Setter Property="BorderThickness" Value="1 1 1 1"/>
						<Setter Property="Background" Value="#2B9148"/>
						<Setter Property="CornerRadius" Value="5"/>
					</Style>
					<Style TargetType="{x:Type StackPanel}" x:Key="IN.PANEL">
						<Setter Property="VerticalAlignment" Value="Center"/>
						<Setter Property="Orientation" Value="Horizontal"/>
					</Style>
					<Style TargetType="{x:Type Viewbox}" x:Key="IN.VBOX">
						<Setter Property="VerticalAlignment" Value="Center"/>
						<Setter Property="Margin" Value="12 0 4 0"/>
						<Setter Property="Width" Value="16"/>
						<Setter Property="Height" Value="16"/>
					</Style>
					<Style TargetType="{x:Type Path}" x:Key="IN.PATH">
						<Setter Property="Data" Value="{StaticResource ICON}"/>
						<Setter Property="Width" Value="24"/>
						<Setter Property="Height" Value="24"/>
						<Setter Property="Fill" Value="#FFFFFF"/>
					</Style>
					<Style TargetType="{x:Type ContentPresenter}" x:Key="IN">
						<Setter Property="VerticalAlignment" Value="Center"/>
						<Setter Property="Margin" Value="0 6 12 6"/>
					</Style>
				</ControlTemplate.Resources>
                <Border Style="{StaticResource IN.BORDER}">
					<StackPanel Style="{StaticResource IN.PANEL}">
						<Viewbox Style="{StaticResource IN.VBOX}">
							<Path Style="{StaticResource IN.PATH}"/>
						</Viewbox>
						<ContentPresenter Style="{StaticResource IN}"/>
					</StackPanel>
				</Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

ControlTemplate ์˜์—ญ ํ•˜์œ„ ์ปจํŠธ๋กค ์Šคํƒ€์ผ

x:Key TargetType Remark
IN.BORDER Border CornerRadius=โ€œ5 5 5 5โ€
IN.PANEL StackPanel Orientation=โ€œHorizontalโ€
IN.VBOX ViewBox W16 x H16
IN.PATH Path W24 x H24 (์‹ค์ œ .svg size)
IN ContentPresenter ContentSource=โ€œContentโ€

WPF ์‹คํ–‰ ๊ฒฐ๊ณผ
TBDโ€ฆ

image

:point_right: GitHub ์†Œ์Šค์ฝ”๋“œ

TBDโ€ฆ

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