728x90

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

 

 

728x90
728x90

xaml에서 비슷한 두 개의 코드에 style을 적용시켰는데, 하나의 코드에서는 동작하고 하나의 코드에서는 동작을 하지 않았습니다. 이유를 간단하게 정리해 보고자 합니다.


저에겐 MouseOver 시, 글씨를 굵게 만들어주는 Style이 하나 있습니다.

 

<Style x:Key="DefaultButton" TargetType="Button">
    <Setter Property="Background" Value="DodgerBlue"/>
    <Setter Property="Foreground" Value="#FFFFFF"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="Button">
                <Border x:Name="Border" 
                        Background="{TemplateBinding Background}"
                        BorderBrush="{TemplateBinding BorderBrush}"
                        CornerRadius="5">
                    <ContentPresenter HorizontalAlignment="Center" 
                                      VerticalAlignment="Center"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsMouseOver" Value="True">
                        <Setter Property="FontWeight" Value="Bold" />
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

 

스타일을 한 번 정의해두면, 여러 UI 요소에 동일한 스타일을 적용할 수 있어 코드의 재사용성이 높아집니다.

 

DodgerBlue 색상의 호버 효과가 있는 버튼은 이제 저에게 식은죽 먹기가 됩니다.

 

<Button Style="{StaticResource DefaultButton}">
    <TextBlock Text="Hello"/>
</Button>
<Button Style="{StaticResource DefaultButton}"
        Content="Hello"
        >

 

 

하지만, 아래 코드에서는 Button안의 TextBlock에 FontWeight를 직접적으로 명시했다가는 DodgerBlue 색상만 가진 버튼이 됩니다.

 

<Button Style="{StaticResource DefaultButton}">
    <TextBlock Text="Hello"
               FontWeight="Light"
               />
</Button>
<Button Style="{StaticResource DefaultButton}"
        Content="Hello"
        FontWeight="Light"
        >

 

그 차이를 간단히 정리해 보고자 합니다.

 

먼저, Sytle에 설정된 내용을 간력히 정리해보면, 다음과 같습니다.

 

 

1. ControlTemplate

Control Template , 즉 <> 태그의 외형을 정의합니다.

ControlTemplate을 사용할 경우, 기본 Template을 덮어씁니다.

 

2. ContentPresenter

새로운 Template을 만들어 사용할 경우, 내용(Content)을 표시하는 기능인 ContentPresenter도 함께 선언해야 합니다.

 

3. TemplateBinding

ControlTemplate 안에서 외부의 속성 값을 바인딩할 때 사용합니다.

여기서는 DefaultButton을 사용한 Button의 Background인 DodgerBlue를 참조하게 됩니다.

 

4. Trigger

마지막으로 trigger는 특정 조건이 만족될 때(여기서는 마우스가 버튼 위에 올라왔을 때) 스타일이나 속성을 변경합니다. 이를 통해 ControlTemplate에서 설정된 속성들을 변경할 수 있습니다.

 

 

1번 코드와 2번 코드는 Button 안의 TextBlock에 FontWeight를 직접 설정했느냐의 차이가 있습니다.

 

1번은

  Complate.Trigger → Button 속성 변경 → ContentPresenter: 변경된 속성을 Button의 자식 요소인 TextBlock에 전달합니다.

2번은

  Complate.Trigger → Button 속성 변경 → ContentPresenter: 변경된 속성을 Button의 자식 요소인 TextBlock에 전달합니다. 하지만, 자식 요소에서 직접 설정된 속성은 ControlTemplate의 외부에서 설정된 것으로 간주되어, ControlTemplate의 트리거에서 영향을 받지 않습니다. 

 

간단하게 정리하면, ControlTemplate은 전체적인 Template를 control할 수 있지만, <> 안에서 직접 설정된 요소는 변경할 수 없습니다.

 

 

 

📚 참고 자료

 

[c# wpf] Control Template 란? / 사용방법 (with Style)

이 글을 읽기 전 선수 지식 포스팅 [c# wpf] Style 태그 사용 방법 [c# wpf] Style 상속 방법(with BasedOn) [c# wpf] StaticResource란? (DynamicResource 비교) 왼쪽 그림은 우리가 아는 기본적인 버튼에 빨간 배경색을

yeko90.tistory.com

 

728x90

'C# > WPF' 카테고리의 다른 글

[WPF] Dependency Property  (0) 2024.07.07
[WPF] 생성자 단위 초기화와 필드 단위 초기화  (0) 2024.06.04
[WPF] MVVM 패턴에서의 전체 선택  (0) 2024.05.19
[WPF] ObservableCollection  (0) 2024.05.15
[WPF] View, ViewModel Singleton  (0) 2024.05.12
728x90

현재 프로젝트를 진행하고 있는데, 특정 API를 호출해서 사용하고 있습니다.

 

무얼 정리하면 좋을까하다가 java와 달리 C#에서는 필드라는 개념이 추가적으로 있는데, 이와 관련하여 정리해보고자 합니다.

 


생성자를 이용한 초기화

1
2
3
4
5
6
7
8
9
10
11
private string _initializationConstructor;
public string InitializationConstructor
{
    get { return _initializationConstructor; }
    set { _initializationConstructor = value; }
}
 
public ViewModelMain()
{
    InitializationConstructor = "Initialize with Constructor";
}

특징

 * 생성자 매개변수를 통해 초기값을 유연하게 설정

 * 클래스의 필드 및 속성 초기화가 모두 끝난 후에 생성자가 호출

 

 

필드에서의 직접 초기화

1
2
3
4
5
6
7
private string _initializationField = "Initialize with Field";
 
public string InitializationField
{
    get { return _initializationField; }
    set { _initializationField = value; }
}

특징

 * 간단한 값을 초기화할 때 사용

 * 생성자 호출 전에 초기화

 

만일 필드에서의 초기값과 생성자를 활용한 초기값을 한 번에 설정한다면?

생성자는 필드 및 속성 초기화가 끝난 후에 호출되기 때문에, 필드 초기화한 값을 생성자에서 다시 설정할 경우 생성자 기준으로 값이 설정됨

 

728x90

'C# > WPF' 카테고리의 다른 글

[WPF] Dependency Property  (0) 2024.07.07
[WPF] ControlTemplate의 영향력  (0) 2024.06.30
[WPF] MVVM 패턴에서의 전체 선택  (0) 2024.05.19
[WPF] ObservableCollection  (0) 2024.05.15
[WPF] View, ViewModel Singleton  (0) 2024.05.12
728x90

이번 프로젝트에서는 수동 전체 선택을 구현하게 되었습니다.

 

🤹장작 6시간의 대장정..

 

 


 

무엇이 문제이고, 어떻게 해결했는지 정리해봅니다.

 

사실 전체 선택을 누르면 전체가 선택되고, 전체 선택을 해제하면 전체가 해제되도록 만드는 것은 쉽습니다.

View

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<Window>
    <Grid>
        <StackPanel Orientation="Vertical">
            <CheckBox Content="All"
                      IsChecked="{Binding IsAllChecked, Mode=TwoWay}"
                      />
            <Separator/>
            <CheckBox Content="1"
                      IsChecked="{Binding IsOneChecked, Mode=TwoWay}"                      
                      />
            <CheckBox Content="2"
                      IsChecked="{Binding IsTwoChecked, Mode=TwoWay}"
                      />
            <CheckBox Content="3"
                      IsChecked="{Binding IsThreeChecked, Mode=TwoWay}"
                      />
            <CheckBox Content="4"
                      IsChecked="{Binding IsFourChecked, Mode=TwoWay}"
                      />
        </StackPanel>
    </Grid>
</Window>

 

ViewModel

1
2
3
4
5
6
7
private void ChangeCheckboxFromAll()
{
    IsOneChecked = IsAllChecked;
    IsTwoChecked = IsAllChecked;
    IsThreeChecked = IsAllChecked;
    IsFourChecked = IsAllChecked;
}

 

AllCheckbox에 변경이 일어날 때마다 ChangeCheckboxFromAll 메서드를 실행해서 각 Checkbox의 값을 업데이트 시켜주면 되기 때문이죠.

 

🫠 하지만, 문제는 개별 선택 변경으로 인한 전체 선택 변경에서 일어납니다.

즉, 1, 2, 3만 선택한 상황에서 4를 추가로 선택하면 전체 선택이 표시되어야 하고

전체 선택 된 상태에서 4를 체크 해제하면 전체 선택이 해제 되어야 합니다.

 

그래서 다음과 같이 코드를 추가하면,

ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private void ChangeCheckboxFromAll()
{
    IsOneChecked = IsAllChecked;
    IsTwoChecked = IsAllChecked;
    IsThreeChecked = IsAllChecked;
    IsFourChecked = IsAllChecked;
}
 
private void ChangeCheckboxFromEach()
{
    bool alreadyCheckedAll = IsOneChecked && IsTwoChecked && IsThreeChecked && IsFourChecked;
 
    if (IsAllChecked == alreadyCheckedAll)
    {
        return;
    }
    else
    {
        IsAllChecked = alreadyCheckedAll;
    }
 
}

 

개별 체크 박스마다 ChangeCheckboxFromEach를 연결하면, 개별 체크 박스의 상태 변화를 All Checkbox와 연결지을 수 있습니다.

 

☠️ 그러나, 그 때부터 문제는 시작됩니다.

왜냐면 전체 선택 체크박스 체크 → ChangeCheckFromAll()→ 1번 체크박스 체크 → ChangeCheckFromEach(): else 구문 실행 → 전체 선택 체크박스 체크 해제 → ChangeCheckFromAll()→ 1번 체크박스 체크 해제 → ChangeCheckFromEach(): if 구문 실행

 

결국 전체 선택 체크박스는 체크가 안되고 끝이 납니다...

안녕 전체 선택..👋

 

다른 방법을 찾아보았지만, 최대한 간단하게 끝내고 싶은 마음에 플래그를 사용하는 것으로 합의를 보았습니다.

인터페이스를 활용한 방법도 있었는데, 궁금하신 분들을 아래 주소로 들어가보시면 됩니다.

 

전체 선택 체크박스 로직 - 2

1. 문제의 시작. 지인이 체크박스 동작이 이상하다고 해서 잠깐 봐줬는데 전체 선택/해제 체크 박스를 만들...

blog.naver.com

 

ViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public event PropertyChangedEventHandler PropertyChanged;
 
private bool _ignoreCheckAll;
 
private bool _isAllChecked;
 
public bool IsAllChecked
{
    get => _isAllChecked;
    set
    {
        if (_isAllChecked != value)
        {
            _isAllChecked = value;
            OnPropertyChanged(nameof(IsAllChecked));
            if (!_ignoreCheckAll)
            {
                _ignoreCheckAll = true;
                IsOneChecked = value;
                IsTwoChecked = value;
                IsThreeChecked = value;
                IsFourChecked = value;
                _ignoreCheckAll = false;
            }
        }
    }
}
 
private bool _isOneChecked;
 
public bool IsOneChecked
{
    get => _isOneChecked;
    set
    {
        if (_isOneChecked != value)
        {
            _isOneChecked = value;
            OnPropertyChanged(nameof(IsOneChecked));
            UpdateIsAllChecked();
        }
    }
}
 
private bool _isTwoChecked;
 
public bool IsTwoChecked
{
    get => _isTwoChecked;
    set
    {
        if (_isTwoChecked != value)
        {
            _isTwoChecked = value;
            OnPropertyChanged(nameof(IsTwoChecked));
            UpdateIsAllChecked();
        }
    }
}
 
private bool _isThreeChecked;
 
public bool IsThreeChecked
{
    get => _isThreeChecked;
    set
    {
        if (_isThreeChecked != value)
        {
            _isThreeChecked = value;
            OnPropertyChanged(nameof(IsThreeChecked));
            UpdateIsAllChecked();
        }
    }
}
 
private bool _isFourChecked;
 
public bool IsFourChecked
{
    get => _isFourChecked;
    set
    {
        if (_isFourChecked != value)
        {
            _isFourChecked = value;
            OnPropertyChanged(nameof(IsFourChecked));
            UpdateIsAllChecked();
        }
    }
}
 
private void UpdateIsAllChecked()
{
    if (!_ignoreCheckAll)
    {
        _ignoreCheckAll = true;
        IsAllChecked = _isOneChecked && _isTwoChecked && _isThreeChecked && _isFourChecked;
        _ignoreCheckAll = false;
    }
}

 

중요한 점은 전체 선택 체크 박스를 클릭해서 일어난 상태변화는 다시 전체 선택 체크 박스에 영향을 미치지 않도록 하는 것입니다.

 

따라서 _ignoreCheckAll을 플래그로 선언해서 전체 선택 체크 박스를 클릭해서 일어난 개별 체크 박스의 상태변화가 다시 전체 선택 체크박스로 오지 않도록 막았습니다.

 

물론 이 방법은 체크박스와 관련된 모든 checkbox의 상태 변화 발생 시, 메서드를 호출하므로 성능 저하 문제가 발생할 수도 있겠지만 작은 데이터 규모에서는, 그리고 달리 방도를 못찾은 상황에서는 대안으로 사용할 수 있습니다🤓.

 

 

 

⭐ 오늘의 교훈: 메서드 간 상호 호출 현상을 방지하는 방법 중 하나는 Flag를 이용하는 것이다.

 

728x90

'C# > WPF' 카테고리의 다른 글

[WPF] ControlTemplate의 영향력  (0) 2024.06.30
[WPF] 생성자 단위 초기화와 필드 단위 초기화  (0) 2024.06.04
[WPF] ObservableCollection  (0) 2024.05.15
[WPF] View, ViewModel Singleton  (0) 2024.05.12
[WPF] 생성자 Overloading (2)  (0) 2024.05.11
728x90

WPF를 사용하면서 처음 알게 된 ObservableCollection 클래스와 프로젝트 진행 시, 헤맸던 부분을 정리해봅니다.

 

1. ObservableCollection Class

항목이 추가 또는 제거되거나 전체 목록을 새로 고칠 때 알림을 제공하는 동적 데이터 컬렉션

 

저는 프로젝트를 진행할 때, MVVM 패턴에 맞춰서 진행을 하다보니 처음에 가장 어려웠던 점은 VIew와 ViewModel의 연동이었습니다. 대표적으로 ViewModel 단에서 데이터가 변경되어도 View 즉, UI에는 반영이 안되는 것이죠.

(🥸 리액트 배울 때는 State에 설정만 해주면 페이지 고침없이도 딴딴하고 바뀌는데,, 라는 생각을 잠깐 했습니다.)

 

보통은 이럴 때, INotifyPropertyChanged를 구현해서 ViewModel 데이터 변경 시, UI에 알림을 보내는데, 여러 개의 데이터를 저장하는 List 타입도 마찬가지입니다.

 

그러나, 이 때 ObservableCollection을 사용한다면 INotifyPropertyChanged 사용하지 않고도 데이터 변경 시 자동으로 UI에 업데이트 됩니다(왜냐면, ObservableCollection 내에서 INotifyPropertyChanged를 구현했기 때문입니다😄).

 

 

2. ObservableCollection 특징

 * 자동 UI 업데이트: 데이터 변경 시, View에 자동 반영

 * 일반 컬렉션과 높은 호환성: List 등 기존 컬렉션을 ObservableCollection로 쉽게 변경 가능

 * 항목이 추가, 삭제, 변경될 때마다 이벤트가 발생하므로 대량의 데이터를 빠른 속도로 변경해야 하는 경우 성능 저하의 원인이 될 수 있음

 * 스레드 안전성: 여러 스레드에서 동시에 접근하고 변경하는 경우, 동기화 처리를 직접해야 함

 

 

3. ObservableCollection 사용 시, 어려웠던 점

프로젝트를 하면서 ObservableCollection 사용 시, 처음에 가장 당황했던 부분은 데이터가 변경되었는데 UI변경이 일어나지 않는 것입니다☠️.

 

정확히는 인스턴스 자체가 변경되면 UI에 반영이 되지 않는다는 것입니다.

이는 ObservableCollection<T>이 항목의 추가, 삭제, 수정에 대한 알림을 제공하지만, 컬렉션 인스턴스 자체의 참조 변경에 대해서는 알림을 제공하지 않기 때문입니다.

 

따라서,

MyCollection = new ObservableCollection<MyObject>();

 

새로운 ObservableCollection을 만들어 할당할 경우, UI는 변경되지 않으므로

private ObservableCollection<MyObject> myCollection;
public ObservableCollection<MyObject> MyCollection
{
    get { return myCollection; }
    set
    {
        if (myCollection != value)
        {
            myCollection = value;
            OnPropertyChanged(nameof(MyCollection));
        }
    }
}

 

이렇게 ObservableCollection 자체를 다시 한 번 INotifyPropertyChanged 처리를 해줘야 합니다.

 

그래서 ObservableCollection을 도중에 초기화해줄 때에도, 변경 감지를 위해 저는 새 인스턴스보단 Clear 메서드를 사용합니다.

public void ClearData()
{
    MyCollection.Clear();
}

 

Clear 메서드 사용의 장점으로는

 * UI 자동 업데이트: 컬렉션을 비우는 것이 UI에 즉시 반영됩니다.

 * 메모리 관리: 새 인스턴스를 생성하고 기존 인스턴스를 버리면, 가비지 컬렉터가 기존 인스턴스를 수집할 때까지 해당 메모리가 여전히 사용 중인 상태로 남게 됩니다. 반면, Clear 메서드를 사용하면 기존 컬렉션 인스턴스를 재사용하므로 불필요한 메모리 할당을 줄일 수 있습니다.

 * 코드 가독성 및 유지보수: Clear 메서드를 사용하는 것은 컬렉션의 내용을 초기화하려는 의도를 명확하게 표현합니다.

 

 

 

📚 참고 자료

 

ObservableCollection<T> 클래스 (System.Collections.ObjectModel)

항목이 추가 또는 제거되거나 전체 목록을 새로 고칠 때 알림을 제공하는 동적 데이터 컬렉션을 나타냅니다.

learn.microsoft.com

 

728x90

'C# > WPF' 카테고리의 다른 글

[WPF] 생성자 단위 초기화와 필드 단위 초기화  (0) 2024.06.04
[WPF] MVVM 패턴에서의 전체 선택  (0) 2024.05.19
[WPF] View, ViewModel Singleton  (0) 2024.05.12
[WPF] 생성자 Overloading (2)  (0) 2024.05.11
[WPF] 생성자 Overloading  (1) 2024.04.27