https://www.youtube.com/watch?v=nBjCRGC0Ua8&list=PLlrfTSXS0LLKHfOfwM31jJw3SHuDnkF49&index=10
- 매번 백그라운드 코드에 컬러를 지정하면 MVVC에 위배 되고 번거롭기 때문에 종속성 속성을 사용
- 컨트롤에 Dependency Property를 사용하여 해당 속성을 쉽게 사용할 수 있도록 사용자 정의 속성 생성
해당 엘리먼트의 하위 속성들에도 추가 가능
- WpfAttachedProperty에 클래스파일 ComboBoxBackgroundManager 생성
- prodp 탭탭 했을때 나왔던 아래의 코드는 Register로 종속성 속성을 만들면 해당 사용자 정의 컨트롤에서만 사용가능하다.
public int MyProperty
{
get { return (int)GetValue(MyPropertyProperty); }
set { SetValue(MyPropertyProperty, value); }
}
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.Register("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
- 다른 컨트롤에서도 사용자 커스텀 속성을 범용적으로 사용 할 수 있도록 하고싶을 때 사용하는 것이 Attached Property이다.
📌 Attached Property 구조 만들기
- propa 탭탭을 누르면 기본 구조가 생성된다.
namespace WpfAttachedProperty
{
public class ComboBoxBackgroundManager
{
public static int GetMyProperty(DependencyObject obj)
{
return (int)obj.GetValue(MyPropertyProperty);
}
public static void SetMyProperty(DependencyObject obj, int value)
{
obj.SetValue(MyPropertyProperty, value);
}
// Using a DependencyProperty as the backing store for MyProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MyPropertyProperty =
DependencyProperty.RegisterAttached("MyProperty", typeof(int), typeof(ownerclass), new PropertyMetadata(0));
}
}
- 여기서 자료형은 네군데가 모두 같아야하고 typeof 안의 ownerclass에는 클래스명이와야한다
- ComboBoxBackgroundManager.cs
namespace WpfAttachedProperty
{
public class ComboBoxBackgroundManager
{
public static Brush GetBackground (DependencyObject obj)
{
return (Brush)obj.GetValue(BackgroundProperty);
}
public static void SetBackground(DependencyObject obj, Brush value)
{
obj.SetValue(BackgroundProperty, value);
}
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.RegisterAttached("Background", typeof(Brush), typeof(ComboBoxBackgroundManager), new UIPropertyMetadata(Brushes.Transparent));
}
}
- 이 속성을 사용하고 싶은 엘리먼트로 들어가서 local 로 지정을 해 준다.
- MainWindow.xaml
<StackPanel>
<TextBlock Text="combobox"/>
<ComboBox x:Name="cmb"
IsEditable="True"
Background="Red"
Margin="5 0"
local:ComboBoxBackgroundManager.Background="Red"/>
</StackPanel>
📌 BackgroundProperty가 추가 되었을 때 실행 될 이벤트 만들기
- xaml에서 컬러를 지정했기 때문에 이벤트 발생 DependencyObject는 해당 속성이 발생된 해당 엘리먼트가 된다. (combobox)
- ComboBoxBackgroundManager.cs
//BackgroundProperty가 추가 되었을 때 실행 될 이벤트
private static void BackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//콤보박스로 형변환
var cmb = d as ComboBox;
if (cmb == null) return;
//아까 넘겼던 red가 NewValue가 된다.
//oldValue는 그 전에 있던 값 (기본값으로 지정하였던 Transparent가 됨)
if (e.NewValue != e.OldValue)
{
//색을 여러번 바꾸면 이벤트가 중첩되기 때문에 이벤트를 먼저 지운 후 생성한다.
cmb.Loaded -= Cmb_Loaded;
cmb.Loaded += Cmb_Loaded;
cmb.Unloaded -= Cmb_Unloaded;
cmb.Unloaded += Cmb_Unloaded;
}
private static void Cmb_Unloaded(object sender, RoutedEventArgs e)
{
//종료되면 이벤트를 지우고 메모리를 제거
throw new NotImplementedException();
}
private static void Cmb_Loaded(object sender, RoutedEventArgs e)
{
//sender 는 Combobox가 된다.
var cmb = (ComboBox)sender;
cmb.SetBackground(Brushes.Red);
}
- NewValue가 Cmb_Loaded의 cmb.SetBackground의 Brushes를 가리키고있기때문에 NewValue를 ComboboxLoaded로 전달을 해줘야한다.
- ComboBoxBackgroundManager.cs
namespace WpfAttachedProperty
{
public class ComboBoxBackgroundManager
{
private static Brush? _newBrush = null;
...
그리고 기본 브러쉬를 할당시켜준다.
_newBrush 가 null이면 Treansparent로 설정한다.
- ComboBoxBackgroundManager.cs
private static void BackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var cmb = d as ComboBox;
if (cmb == null) return;
if (e.NewValue != e.OldValue)
{
//brush 색깔이 바뀌면 NewValue에 색깔 전달
_newBrush = (Brush)e.NewValue;
...
private static void Cmb_Loaded(object sender, RoutedEventArgs e)
{
//sender 는 Combobox가 된다.
var cmb = (ComboBox)sender;
//전달된 값은 로드가 되는 경우 SetBackground 확장 함수에 추가되어 Combobox 색상 변경
cmb.SetBackground(_newBrush ?? Brushes.Transparent);
}
- ComboBoxBackgroundManager.cs
private static void Cmb_Unloaded(object sender, RoutedEventArgs e)
{
//종료되면 이벤트를 지우고 메모리를 제거
var cmb = (ComboBox)sender;
cmb.Loaded -= Cmb_Loaded;
cmb.Unloaded -= Cmb_Unloaded;
_newBrush = null;
}
- ComboBoxBackgroundManager.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
namespace WpfAttachedProperty
{
public class ComboBoxBackgroundManager
{
private static Brush? _newBrush = null;
public static Brush GetBackground(DependencyObject obj)
{
return (Brush)obj.GetValue(BackgroundProperty);
}
public static void SetBackground(DependencyObject obj, Brush value)
{
obj.SetValue(BackgroundProperty, value);
}
// Using a DependencyProperty as the backing store for Background. This enables animation, styling, binding, etc...
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.RegisterAttached("Background", typeof(Brush), typeof(ComboBoxBackgroundManager), new UIPropertyMetadata(Brushes.Transparent, BackgroundChanged));
private static void BackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var cmb = d as ComboBox;
if (cmb == null) return;
if (e.NewValue != e.OldValue)
{
_newBrush = (Brush)e.NewValue;
cmb.Loaded -= Cmb_Loaded;
cmb.Loaded += Cmb_Loaded;
cmb.Unloaded -= Cmb_Unloaded;
cmb.Unloaded += Cmb_Unloaded;
}
}
private static void Cmb_Unloaded(object sender, RoutedEventArgs e)
{
var cmb = (ComboBox)sender;
cmb.Loaded -= Cmb_Loaded;
cmb.Unloaded -= Cmb_Unloaded;
_newBrush = null;
}
private static void Cmb_Loaded(object sender, RoutedEventArgs e)
{
var cmb = (ComboBox)sender;
cmb.SetBackground(_newBrush ?? Brushes.Transparent);
}
}
}
- 비하인드 코드에 작성했던 색상 지정은 삭제해준다.
-MainWindow.xaml.cs
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
}
- MainWindowd에도 지정했던 컬러 코드를 삭제해준 뒤 실행을 해 본다.
- MainWindow.xaml
<StackPanel>
<TextBlock Text="combobox"/>
<ComboBox x:Name="cmb"
IsEditable="True"
Margin="5 0"
local:ComboBoxBackgroundManager.Background="Red"/>
</StackPanel>
📌 (예제) 폼을 하나 더 추가 해 보기
- WpfAttachedProperty에 창 파일 MainView2 추가
- MainWindow.xaml
<StackPanel>
<TextBlock Text="combobox"/>
<Button Content="ToView2" Click="Button_Click"/>
</StackPanel>
- MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Loaded += MainWindow_Loaded;
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
}
private void Button_Click(object sender, RoutedEventArgs e)
{
var view2 = new MainView2();
view2.Show();
}
}
-MainView2.xaml
<Grid>
<ComboBox local:ComboBoxBackgroundManager.Background="Red"/>
</Grid>
-MainView2.xaml.cs
namespace WpfAttachedProperty
{
/// <summary>
/// MainView2.xaml에 대한 상호 작용 논리
/// </summary>
public partial class MainView2 : Window
{
public MainView2()
{
InitializeComponent();
}
}
}
실행을 해 보면 BackgroundChanged가 발생되어 Load되면서 Background를 적용시킨다.