본문 바로가기

개인공부/WPF

[WPF] 의존 속성(DependencyProperty)

■ 의존 속성(DependencyProperty)란?

Property 값이 변경되었을 때, 자동으로 어떤 작업을 처리해 주는 것
스타일 지정, 데이터 바인딩, 애니메이션 처리 등에 사용됩니다.

 

DependencyProperty 사용 방법

 - DependencyProperty 정의

public static readonly DependencyProperty sampleDataProperty = DependencyProperty.Register(
            "sampleData", // (1)
            typeof(string), // (2)
            typeof(MainWindow), // (3)
            new FrameworkPropertyMetadata(
                null,  // (4)
                new PropertyChangedCallback(SampleDataPropertyChanged)  // (5)
                ) 
            );

  (1) DependencyProperty로 등록할 Wrapper 속성 이름

  (2) DependencyProperty 속성 타입

  (3) DependencyProperty가 속해있는 ownerType

  (4) 속성의 초기값

  (5) 속성이 변경될 때 호출할 callback method

   * (4), (5)을 정의한 PropertyMetadata는 선택 사항

 

 - DependencyProperty로 사용할 속성

public string sampleData
        {
            get { return (string)GetValue(sampleDataProperty); }
            set { SetValue(sampleDataProperty, value); }
        }

    · GetValue, SetValue로 DependencyProperty 연결

 

 - DependencyProperty에 사용될 callback method 정의

private static void SampleDataPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        { 
            // callback 내용 정의
        }

 

 

■ DependencyProperty Example 

 - Example 설명

   · 색상(radiobutton), 적용할 영역(checkbox)를 선택 후 적용(button) 버튼 클릭

   · 선택한 색상과 영역 정보를 DependencyProperty로 정의한 selectColor, checkStatus 값에 할당

   · selectColor, checkStatus의 값이 변경될 때마다 callback method 호출

   · callback method에 정의된 '적용 버튼' 하단의 line 박스 색상 변경 및 이전 상태 표기

 

 

 - MainWindow.xaml

MainWindow.xaml 디자인

<Window x:Class="DependencyPropertyEx.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:DependencyPropertyEx"
        mc:Ignorable="d"
        Title="MainWindow" Height="400" Width="400">
    
    <StackPanel VerticalAlignment="Center">
            <StackPanel x:Name="radioGroup" Orientation="Horizontal" 
                        HorizontalAlignment="Center" VerticalAlignment="Center">
                <RadioButton GroupName="colorGroup" Content="Red" Margin="5,5,5,5"/>
                <RadioButton GroupName="colorGroup" Content="Blue" Margin="5,5,5,5"/>
                <RadioButton GroupName="colorGroup" Content="Yellow" Margin="5,5,5,5"/>
                <RadioButton GroupName="colorGroup" Content="Green" Margin="5,5,5,5"/>
            </StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" 
                    VerticalAlignment="Center">
            <CheckBox x:Name="chk_01" Content="Line_01" Margin="5,5,5,5"/>
            <CheckBox x:Name="chk_02" Content="Line_02" Margin="5,5,5,5"/>
            <CheckBox x:Name="chk_03" Content="Line_03" Margin="5,5,5,5"/>
            <CheckBox x:Name="chk_04" Content="Line_04" Margin="5,5,5,5"/>
        </StackPanel>
        <Button Content="적용" Click="Button_Click" Margin="5,5,5,5"/>
        <Grid x:Name="SelectedColorGrid" Margin="5,0,5,0">
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Border x:Name="br_01" BorderBrush="Gray" BorderThickness="1" 
                    Grid.Row="0" Grid.Column="0" Margin="1,0,1,0">
                <Label Content="Line_01" VerticalContentAlignment="Center" 
                       HorizontalContentAlignment="Center" Height="200"/>
            </Border>
            <Border x:Name="br_02" BorderBrush="Gray" BorderThickness="1" 
                    Grid.Row="0" Grid.Column="1" Margin="1,0,1,0">
                <Label Content="Line_02"  VerticalContentAlignment="Center" 
                       HorizontalContentAlignment="Center" Height="200"/>
            </Border>
            <Border x:Name="br_03" BorderBrush="Gray" BorderThickness="1" 
                    Grid.Row="0" Grid.Column="2" Margin="1,0,1,0">
                <Label Content="Line_03" VerticalContentAlignment="Center" 
                       HorizontalContentAlignment="Center" Height="200"/>
            </Border>
            <Border x:Name="br_04" BorderBrush="Gray" BorderThickness="1" 
                    Grid.Row="0" Grid.Column="3" Margin="1,0,1,0">
                <Label Content="Line_04" VerticalContentAlignment="Center"
                       HorizontalContentAlignment="Center" Height="200"/>
            </Border>
        </Grid>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" 
                    VerticalAlignment="Center" Margin="5,5,5,5">
            <Label Content="이전 색상 : "/>
            <Label x:Name="oldColor"/>
            <Label Content=" / "/>
            <Label Content="현재 색상 : "/>
            <Label x:Name="newColor"/>
            <Label Content=""/>
        </StackPanel>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Label Content="이전 Line : "/>
            <CheckBox x:Name="old_chk_01" Content="Line_01" IsEnabled="False" Margin="5,5,5,5"/>
            <CheckBox x:Name="old_chk_02" Content="Line_02" IsEnabled="False" Margin="5,5,5,5"/>
            <CheckBox x:Name="old_chk_03" Content="Line_03" IsEnabled="False" Margin="5,5,5,5"/>
            <CheckBox x:Name="old_chk_04" Content="Line_04" IsEnabled="False" Margin="5,5,5,5"/>
        </StackPanel>
    </StackPanel>
</Window>

 

 

 - MainWindow.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace DependencyPropertyEx
{
    public class CheckBoxStatus
    {
        public bool chk_01 { get; set; }
        public bool chk_02 { get; set; }
        public bool chk_03 { get; set; }
        public bool chk_04 { get; set; }
    }

    public partial class MainWindow : Window
    {
        private static SolidColorBrush solidColor;
        private static SolidColorBrush defaultColor = new SolidColorBrush(Colors.Gray);

        public string selectColor
        {
            get { return (string)GetValue(selectColorProperty); }
            set { SetValue(selectColorProperty, value); }
        }

        public static readonly DependencyProperty selectColorProperty = DependencyProperty.Register(
            "selectColor", // DependencyProperty로 등록할 Wrapper 속성 이름
            typeof(string), // DependencyProperty 속성 타입
            typeof(MainWindow), // DependencyProperty가 속해있는 ownerType
            new FrameworkPropertyMetadata(null, new PropertyChangedCallback(SelectColorPropertyChanged))
            ); // FrameworkPropertyMetadata(속성의 초기값, 속성이 변경 될때 호출할 callback method)

        public CheckBoxStatus checkStatus
        {
            get { return (CheckBoxStatus)GetValue(checkStatusProperty); }
            set { SetValue(checkStatusProperty, value); }
        }

        public static readonly DependencyProperty checkStatusProperty = DependencyProperty.Register(
            "checkStatus", // DependencyProperty로 등록할 Wrapper 속성 이름
            typeof(CheckBoxStatus), // DependencyProperty 속성 타입
            typeof(MainWindow), // DependencyProperty가 속해있는 ownerType
            new FrameworkPropertyMetadata(new PropertyChangedCallback(CheckStatusPropertyChanged))
            ); // FrameworkPropertyMetadata(속성이 변경 될때 호출할 callback method)
               


        // selectColor에 변화가 있으면 호출하는 callback method
        private static void SelectColorPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            MainWindow mainWindow = obj as MainWindow;

            // 이전 색상 정보
            if (e.OldValue == null)
                mainWindow.oldColor.Content = "없음";
            else
            {
                mainWindow.oldColor.Content = e.OldValue.ToString();
                mainWindow.oldColor.Foreground = 
                    (SolidColorBrush)new BrushConverter().ConvertFromString(e.OldValue.ToString());
            }

            // 새로운 색상 정보
            mainWindow.newColor.Content = e.NewValue.ToString();

            solidColor = (SolidColorBrush)new BrushConverter().ConvertFromString(e.NewValue.ToString());
            mainWindow.newColor.Foreground = solidColor;

            // checkbox 선택 확인 후 색상 적용
            mainWindow.br_01.BorderBrush = (mainWindow.chk_01.IsChecked == true) ? solidColor : defaultColor;
            mainWindow.br_02.BorderBrush = (mainWindow.chk_02.IsChecked == true) ? solidColor : defaultColor;
            mainWindow.br_03.BorderBrush = (mainWindow.chk_03.IsChecked == true) ? solidColor : defaultColor;
            mainWindow.br_04.BorderBrush = (mainWindow.chk_04.IsChecked == true) ? solidColor : defaultColor;
        }


        // checkStatus 변화가 있으면 호출하는 callback method
        private static void CheckStatusPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            MainWindow mainWindow = obj as MainWindow;

            // 이전 checkbox 정보
            if (e.OldValue == null)
            {
                mainWindow.old_chk_01.IsChecked = false;
                mainWindow.old_chk_02.IsChecked = false;
                mainWindow.old_chk_03.IsChecked = false;
                mainWindow.old_chk_04.IsChecked = false;
            }
            else
            {
                CheckBoxStatus oldStatus = e.OldValue as CheckBoxStatus;
                mainWindow.old_chk_01.IsChecked = (oldStatus.chk_01 == true) ? true : false;
                mainWindow.old_chk_02.IsChecked = (oldStatus.chk_02 == true) ? true : false;
                mainWindow.old_chk_03.IsChecked = (oldStatus.chk_03 == true) ? true : false;
                mainWindow.old_chk_04.IsChecked = (oldStatus.chk_04 == true) ? true : false;
            }

            // checkbox 선택 확인 후 색상 적용
            mainWindow.br_01.BorderBrush = (mainWindow.chk_01.IsChecked == true) ? solidColor : defaultColor;
            mainWindow.br_02.BorderBrush = (mainWindow.chk_02.IsChecked == true) ? solidColor : defaultColor;
            mainWindow.br_03.BorderBrush = (mainWindow.chk_03.IsChecked == true) ? solidColor : defaultColor;
            mainWindow.br_04.BorderBrush = (mainWindow.chk_04.IsChecked == true) ? solidColor : defaultColor;
        }


        public MainWindow()
        {
            InitializeComponent();
        }


        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MainWindow mainWindow = this;

            foreach(RadioButton item in mainWindow.radioGroup.Children)
            {
                if(item.IsChecked == true)
                {
                    selectColor = item.Content.ToString();  // radioButton에서 체크한 색상 정보 대입
                    break;
                }
            }

            // 새로운 CheckBoxStatus 생성, 
            checkStatus = new CheckBoxStatus();
            checkStatus.chk_01 = (mainWindow.chk_01.IsChecked == true) ? true : false;
            checkStatus.chk_02 = (mainWindow.chk_02.IsChecked == true) ? true : false;
            checkStatus.chk_03 = (mainWindow.chk_03.IsChecked == true) ? true : false;
            checkStatus.chk_04 = (mainWindow.chk_04.IsChecked == true) ? true : false;
        }
    }
}

 

 

 - radiobuon(Red), Line01(CheckBox) 선택, 적용

 - radiobuon(Blue), Line01, Line02(CheckBox) 선택, 적용

 - radiobuon(Green), Line01, Line02, Line04(CheckBox) 선택, 적용

 - radiobuon(Yellow), Line01, Line02, Line03, Line04(CheckBox) 선택, 적용

 - radiobuon(Blue), Line01, Line04(CheckBox) 선택, 적용

 

 

 

 

'개인공부 > WPF' 카테고리의 다른 글

[WPF] DataContext  (0) 2022.07.23
[WPF] 이벤트 라우팅, 터널링(Tunneling), 버블링(Bubbling)  (0) 2022.05.29
[WPF] 멀티쓰레드(Multi Thread)  (0) 2022.05.11
[WPF] 데이터 바인딩(Data Binding)  (0) 2022.04.26
[WPF] Hello World  (0) 2022.04.19