728x90
https://www.youtube.com/watch?v=9bzJhogdxVg&list=PLlrfTSXS0LLKHfOfwM31jJw3SHuDnkF49&index=11
📌 ComboBox Control 만들기
- Controls에 사용자 정의 컨트롤 ComboBoxControl 파일 생성
- Commons 파일 생성 및 클래스 ComboBoxColorManager 파일 생성
- Extensions파일에 클래스 ComboBoxExtension 파일 생성
- ComboBoxContorl.xaml
<UserControl x:Class="wpfLib.Controls.ComboBoxControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:wpfLib.Controls"
xmlns:commons="clr-namespace:wpfLib.Commons"
xmlns:converters="clr-namespace:wpfLib.Converters"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
x:Name="root">
<UserControl.Resources>
<converters:ValidatingBorderBrushConverter x:Key="ValidatingBorderBrushConverter"/>
<converters:ValidatingBorderThicknessConverter x:Key="ValidatingBorderThicknessConverter"/>
<Style x:Key="BaseControl" TargetType="{x:Type FrameworkElement}">
<Setter Property="Control.FontSize" Value="{Binding FontSize, ElementName=root}"/>
<Setter Property="Control.FontFamily" Value="{Binding FontFamily, ElementName=root}"/>
</Style>
<!--워터마크가 될 부분-->
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource BaseControl}">
<Setter Property="Text" Value="{Binding WaterMarkText, ElementName=root}"/>
<Setter Property="Foreground" Value="{Binding WaterMarkTextColor, ElementName=root}"/>
<Setter Property="Padding" Value="5 0 0 0"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Text, ElementName=cmb}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
<Style TargetType="{x:Type ComboBox}" BasedOn="{StaticResource BaseControl}">
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="IsEditable" Value="{Binding IsEditable, ElementName=root}"/>
<Setter Property="Text" Value="{Binding Text, ElementName=root, UpdateSourceTrigger=PropertyChanged}"/>
<Setter Property="SelectedItem" Value="{Binding SelectedItem, ElementName=root}"/>
<Setter Property="SelectedIndex" Value="{Binding SelectedIndex, ElementName=root}"/>
<Setter Property="ItemsSource" Value="{Binding ItemsSource, ElementName=root}"/>
<Setter Property="ItemContainerStyle" Value="{Binding ItemContainerStyle, ElementName=root}"/>
<Setter Property="commons:ComboBoxColorManager.Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="0"/>
</Style>
<Style TargetType="{x:Type Border}">
<Setter Property="BorderThickness">
<Setter.Value>
<MultiBinding Converter="{StaticResource ValidatingBorderThicknessConverter}">
<Binding Path="Validating" ElementName="root"/>
<Binding Path="BorderThickness" ElementName="root"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="BorderBrush">
<Setter.Value>
<MultiBinding Converter="{StaticResource ValidatingBorderBrushConverter}">
<Binding Path="Validating" ElementName="root"/>
<Binding Path="BorderBrush" ElementName="root"/>
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid>
<TextBlock x:Name="txt"/>
<Border>
<ComboBox x:Name="cmb"/>
</Border>
</Grid>
</UserControl>
=> 계속 예외처리 오류가 떠서 한참을 고생했는데 맨 위에 x:name="root"를 안해서 그랬었다 ㅡㅡ
- ComboBoxControl.xaml.cs
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace wpfLib.Controls
{
/// <summary>
/// ComboBoxControl.xaml에 대한 상호 작용 논리
/// </summary>
public partial class ComboBoxControl : UserControl
{
public ComboBoxControl()
{
InitializeComponent();
}
#region Static Properties
public static readonly DependencyProperty IsEditableProperty =
DependencyProperty.Register("IsEditable", typeof(bool), typeof(ComboBoxControl), new PropertyMetadata(null));
public static readonly DependencyProperty ValidatingProperty =
DependencyProperty.Register("Validating", typeof(bool), typeof(ComboBoxControl), new PropertyMetadata(null));
public static new readonly DependencyProperty BorderBrushProperty =
DependencyProperty.Register("BorderBrush", typeof(Brush), typeof(ComboBoxControl), new UIPropertyMetadata(Brushes.SkyBlue));
public static new readonly DependencyProperty BorderThicknessProperty =
DependencyProperty.Register("BorderThickness", typeof(Thickness), typeof(ComboBoxControl), new UIPropertyMetadata(new Thickness(1)));
public static readonly DependencyProperty TextProperty =
DependencyProperty.Register("Text", typeof(string), typeof(ComboBoxControl), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
public static readonly DependencyProperty WaterMarkTextProperty =
DependencyProperty.Register("WaterMarkText", typeof(string), typeof(ComboBoxControl), new PropertyMetadata(null));
public static readonly DependencyProperty WaterMarkTextColorProperty =
DependencyProperty.Register("WaterMarkTextColor", typeof(Brush), typeof(ComboBoxControl), new UIPropertyMetadata(Brushes.Gray));
public static readonly DependencyProperty ItemContainerStyleProperty =
DependencyProperty.Register("ItemContainerStyle", typeof(Style), typeof(ComboBoxControl), new PropertyMetadata(null));
public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ComboBoxControl), new PropertyMetadata(null));
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(ComboBoxControl), new PropertyMetadata(null));
public static readonly DependencyProperty SelectedIndexProperty =
DependencyProperty.Register("SelectedIndex", typeof(int), typeof(ComboBoxControl), new PropertyMetadata(null));
#endregion
#region Public Properties
public bool IsEditable
{
get { return (bool)GetValue(IsEditableProperty); }
set { SetValue(IsEditableProperty, value); }
}
public bool Validating
{
get { return (bool)GetValue(ValidatingProperty); }
set { SetValue(ValidatingProperty, value); }
}
public new Brush BorderBrush
{
get { return (Brush)GetValue(BorderBrushProperty); }
set { SetValue(BorderBrushProperty, value); }
}
public new Thickness BorderThickness
{
get { return (Thickness)GetValue(BorderThicknessProperty); }
set { SetValue(BorderThicknessProperty, value); }
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public string WaterMarkText
{
get { return (string)GetValue(WaterMarkTextProperty); }
set { SetValue(WaterMarkTextProperty, value); }
}
public Brush WaterMarkTextColor
{
get { return (Brush)GetValue(WaterMarkTextColorProperty); }
set { SetValue(WaterMarkTextColorProperty, value); }
}
public IEnumerable ItemsSource
{
get { return (IEnumerable)GetValue(ItemsSourceProperty); }
set { SetValue(ItemsSourceProperty, value); }
}
public Style ItemContainerStyle
{
get { return (Style)GetValue(ItemContainerStyleProperty); }
set { SetValue(ItemContainerStyleProperty, value); }
}
public object SelectedItem
{
get { return (object)GetValue(SelectedItemProperty); }
set { SetValue(SelectedItemProperty, value); }
}
public int SelectedIndex
{
get { return (int)GetValue(SelectedIndexProperty); }
set { SetValue(SelectedIndexProperty, value); }
}
#endregion
}
}
- ComboBoxColorManager.cs
namespace wpfLib.Commons
{
public class ComboBoxColorManager
{
// 필드변수
private static Brush? _newBackground;
private static Brush? _newBorderBrush;
// 프로퍼티 기본값은 null로 지정
public static readonly DependencyProperty BackgroundProperty =
DependencyProperty.RegisterAttached("Background", typeof(Brush), typeof(ComboBoxColorManager), new UIPropertyMetadata(null, BackgroundChanged));
public static readonly DependencyProperty BorderBrushProperty =
DependencyProperty.RegisterAttached("BorderBrush", typeof(Brush), typeof(ComboBoxColorManager), new UIPropertyMetadata(null, BorderBrushChanged));
// 메서드
private static void AddEvents(DependencyObject d, DependencyPropertyChangedEventArgs e, Action<Brush> brushCallBack)
{
ComboBox? cmb = d as ComboBox;
if (cmb == null) return;
if (e.NewValue != e.OldValue)
{
brushCallBack?.Invoke((Brush)e.NewValue);
cmb.Loaded -= Cmb_Loaded;
cmb.Unloaded -= Cmb_Unloaded;
cmb.Loaded += Cmb_Loaded;
cmb.Unloaded += Cmb_Unloaded;
}
}
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 Brush GetBorderBrush(DependencyObject obj)
{
return (Brush)obj.GetValue(BorderBrushProperty);
}
public static void SetBorderBrush(DependencyObject obj, Brush value)
{
obj.SetValue(BorderBrushProperty, value);
}
// 이벤트추가
private static void BackgroundChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
//대리자를 이용하여 할당
AddEvents(d, e, brush => _newBackground = brush);
}
private static void BorderBrushChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
AddEvents(d, e, brush => _newBorderBrush = brush);
}
private static void Cmb_Unloaded(object sender, RoutedEventArgs e)
{
//unload 시 메모리에서 지워주기
ComboBox? cmb = (ComboBox)sender;
cmb.Loaded -= Cmb_Loaded;
cmb.Unloaded -= Cmb_Unloaded;
_newBackground = null;
_newBorderBrush = null;
}
private static void Cmb_Loaded(object sender, RoutedEventArgs e)
{
ComboBox? cmb = (ComboBox)sender;
if (_newBackground != null)
{
cmb.SetBackground(_newBackground);
}
if (_newBorderBrush != null)
{
cmb.SetBorderBrush(_newBorderBrush);
}
}
}
}
- ComboBoxExtensions.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls.Primitives;
using System.Windows.Controls;
using System.Windows.Media;
namespace wpfLib.Extensions
{
public static class ComboBoxExtensions
{
public static Border? GetBorder(this ComboBox comboBox)
{
ToggleButton? toggleButton = (ToggleButton?)comboBox.Template?.FindName("toggleButton", comboBox);
return (Border?)toggleButton?.Template?.FindName("templateRoot", toggleButton);
}
public static void SetBorderBrush(this ComboBox comboBox, Brush brush)
{
Border? border = comboBox.GetBorder();
if (border != null)
border.BorderBrush = brush;
}
public static void SetBackground(this ComboBox comboBox, Brush brush)
{
Border? border = comboBox.GetBorder();
if (border != null)
border.Background = brush;
TextBox? textbox = (TextBox)comboBox.Template.FindName("PART_EditableTextBox", comboBox);
if (textbox != null)
{
Border? parent = (Border)textbox.Parent;
parent.Background = brush;
}
}
}
}
- LoginControl.xaml
<controls:ComboBoxControl Background="White"
Height="35"
WaterMarkText="이메일을 입력하세요"
WaterMarkTextColor="blue"
IsEditable="True"/>
📌 ComboBox ItemsSource Binding하기
- LoginControl.xaml
<controls:ComboBoxControl Background="White"
Height="35"
WaterMarkText="이메일을 입력하세요"
WaterMarkTextColor="blue"
IsEditable="True"
ItemsSource="{Binding Emails}"/>
- LoginControlViewModel.cs
namespace seungjjangTalk.ViewModels
{
[ObservableObject]
public partial class LoginControlViewModel
{
[ObservableProperty]
private ObservableCollection<string> _emails;
public LoginControlViewModel()
{
Emails = new ObservableCollection<string>()
{
"test1@test.com",
"test2@test.com"
};
}
}
}
728x90