C#/WPF

[WPF] Dependency Property

HJ0216 2024. 7. 7. 15:00

xaml에서 ⭐나만의 property⭐를 만들 수 있다는 걸 알고 계셨나요?

전 알고 있었습니다. 하지만, ⭐나만의 property⭐가 없어도 구현에 문제가 없어서 Dependency Property를 공부하는 걸 미루다가 프로젝트에서 사용되는 걸 보고, 이 참에 정리하고자 글을 작성해 봅니다.

 

 

 

Dependency Property

  * XAML, C# 코드 비하인드(.xaml.cs)에서 사용 가능

  * 의존속성 값이 변경되면 자동으로 어떤 것을 로드되게 하거나 랜더링 되도록 할 수 있음

    * 애니메이션, 스타일링, 데이터바인딩 등에 자주 사용

  * 기본으로 제공되는 UI 컨트롤은 대부분의 속성이 의존 속성으로 되어 있음

 

 

1. MainWindow에서 바로 사용하기

MainWindow.xaml

<Window x:Class="DependencyPropertyPratice.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:DependencyPropertyPratice"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        >
    <Window.ContextMenu>
        <ContextMenu MenuItem.Click="ContextMenu_Click">
            <MenuItem Header="#02343F"/>
            <MenuItem Header="#F0EDCC"/>
            <MenuItem Header="#0A174E"/>
            <MenuItem Header="#F5D042"/>
        </ContextMenu>
    </Window.ContextMenu>

    <TextBox Name="colorBox"
             VerticalAlignment="Center" HorizontalAlignment="Center"
             Width="150" Height="50"
             />
</Window>

 

MainWindow.xaml.cs

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

namespace DependencyPropertyPratice
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        // DependencyProperty(MyColorProperty)를 위한 래퍼 속성의 MyColor
        // 이 래퍼속성에서는 System.Windows.DependencyObject 클래스의 GetValue()와 SetValue()를 이용해서 get, set을 정의해야 함
        public string MyColor
        {
            get { return (string)GetValue(MyColorProperty); }
            set { SetValue(MyColorProperty, value); }
        }

        // DependencyProperty
        // DependencyProperty 클래스에는 public 생성자가 없으므로 static 메서드인 Register()를 사용해서 등록
        // 수정이 불가능 하도록 의존 속성은 readonly 필드로 선언되는데, 일반 UI 컨트롤 등 대부분의 의존속성은 FrameworkElement에 DependencyProperty로 정의되어 있음
        public static readonly DependencyProperty MyColorProperty = DependencyProperty.Register(
            "MyColor" // 의존 속성으로 등록될 속성
            , typeof(string) // 등록할 의존 속성 타입
            , typeof(MainWindow) // 의존 속성을 소유하게 될 Owner
            , new FrameworkPropertyMetadata(new PropertyChangedCallback(OnMyColorPropertyChanged))
            // 속성값 변경 시, 호출될 메서드
            // Property 값 변경에 따른 Callback() 등 새로운 속성을 추가하기 위해 FrameworkPropertyMetadata를 인자 값으로 전달 할 수 있음
            );

        private static void OnMyColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MainWindow window = d as MainWindow;
            SolidColorBrush brush = (SolidColorBrush)new BrushConverter().ConvertFromString(e.NewValue.ToString());
            window.Background = brush;
            window.Title = (e.OldValue == null) ? "이전 배경색 없음" : e.OldValue.ToString();
            window.colorBox.Text = e.NewValue.ToString();
        }

        private void ContextMenu_Click(object sender, RoutedEventArgs e)
        {
            string selectedColor = (e.Source as MenuItem).Header as string;
            MyColor = selectedColor;
        }

    }
}

 

 

2. SubWindow에서 상속받아서 사용하기

SubWindow.xaml

<local:MainWindow x:Class="DependencyPropertyPratice.WindowSub"
        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:DependencyPropertyPratice"
        mc:Ignorable="d"
        Title="WindowSub" Height="450" Width="800"
        MyColor="#F95700"
        >
    <Grid>
        <Button Content="Go To the Main Window"
                Width="150" Height="30"
                Click="Button_Click"
                />
    </Grid>
</local:MainWindow>

 

☠️ 이렇게 못씁니다.

오류납니다.

'DependencyPropertyPratice.MainWindow' cannot be the root of a XAML file because it was defined using XAML.

 

WPF에서는 XAML 파일을 통해 이미 정의된 클래스를 다시 XAML의 루트 요소로 사용하는 것을 허용하지 않습니다.

 

상속을 받고자 한다면, MainWindow를 XAML이 아닌 코드 비하인드 파일(C# 파일)에서만 정의하여 SubWindow에서 이를 상속할 수 있도록 할 수 있습니다.

 

 

MainWindowOnlyCS.cs

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

namespace DependencyPropertyPratice
{
    public class MainWindowOnlyCS : Window
    {
        public string MyColor
        {
            get { return (string)GetValue(MyColorProperty); }
            set { SetValue(MyColorProperty, value); }
        }

        public static readonly DependencyProperty MyColorProperty = DependencyProperty.Register(
            "MyColor" // 의존 속성으로 등록될 속성
            , typeof(string) // 등록할 의존 속성 타입
            , typeof(MainWindowOnlyCS) // 의존 속성을 소유하게 될 Owner
            , new FrameworkPropertyMetadata(new PropertyChangedCallback(OnMyColorPropertyChanged))
            // 속성값 변경 시, 호출될 메서드
            );

        private static void OnMyColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            MainWindowOnlyCS window = d as MainWindowOnlyCS;
            SolidColorBrush brush = (SolidColorBrush)new BrushConverter().ConvertFromString(e.NewValue.ToString());
            window.Background = brush;
            window.Title = (e.OldValue == null) ? "이전 배경색 없음" : e.OldValue.ToString();
        }
    }
}

 

WindowSub.xaml

<local:MainWindowOnlyCS x:Class="DependencyPropertyPratice.WindowSub"
        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:DependencyPropertyPratice"
        mc:Ignorable="d"
        Title="WindowSub" Height="450" Width="800"
        MyColor="#F95700"
        >
    <Grid>
        <Button Content="Go To the Main Window"
                Width="150" Height="30"
                Click="Button_Click"
                />
    </Grid>
</local:MainWindowOnlyCS>

 

.cs로 이뤄진 Window 파일을 상속받아서 xaml 태그에 MyColor를 전달하면 DependencyProperty에 따라 WindowSub의 배경색이 오랜지 색으로 변경됩니다.

 

 

 

 

📚 참고 자료

 

Reference Source

 

referencesource.microsoft.com