WPF Converter (컨버터, 값 변환기)
Converter
WPF에서 Converter는 WPF의 핵심 기능 중 하나인 데이터 바인딩에서 데이터를 바인딩하는 동안 값의 변환을 수행하는 데 사용되는 기능입니다. Converter를 사용하면 데이터를 원하는 형식으로 변환하거나, 값을 가공하여 UI 요소에 표시할 수 있습니다.
예를 들어, bool 값을 "예" 또는 "아니오"로 변환하거나, 숫자를 포맷팅하거나, 날짜 형식을 변경하는 등의 작업을 수행할 수 있습니다.
사용방법
Converter는 IValueConverter 또는 IMultiValueConverter 인터페이스를 구현하는 클래스로 작성됩니다. IValueConverter는 단일 값을 변환하는 데 쓰이며, IMultiValueConverter는 여러 값을 조합하여 변환하는 데 쓰입니다.
이 인터페이스에는 두 개의 메서드가 있습니다.
1. Convert
데이터 소스에서 UI 요소로 값이 전달될 때 호출되는 메서드입니다. 이 메서드는 변환된 값을 반환합니다. 예를 들어, 숫자를 문자열로 변환하거나, 날짜 형식을 변경하거나, 열거형 값을 텍스트로 변환하는 등의 작업을 수행할 수 있습니다.
2. ConvertBack
UI 요소에서 데이터 소스로 값이 전달될 때 호출되는 메서드입니다. 이 메서드는 다시 원래의 값으로 변환된 값을 반환합니다. 예를 들어, 문자열을 숫자로 변환하거나, 텍스트를 열거형 값으로 변환하는 등의 작업을 수행할 수 있습니다.
데이터 바인딩 표현식에서 Converter를 사용하여 데이터를 변환하는 방법은 다음과 같습니다.
<TextBlock Text="{Binding MyProperty, Converter={StaticResource MyConverter}}" />
위의 예시에서 "MyProperty"는 데이터 소스의 속성을 나타내며, "MyConverter"는 리소스로 선언된 Converter의 이름입니다. Converter는 데이터 소스로부터 값을 가져와서 필요한 변환 작업을 수행한 후에 UI 요소에 표시됩니다.
Converter 종류 및 코드 예시
어떤 것이든 IValueConverter 또는 IMultiValueConverter 인터페이스를 상속해서 직접 만들어도 되며, 몇 가지 일반적인 Converter의 종류는 다음과 같습니다.
1. BooleanConverter
논리값을 다른 형식으로 변환하는 데 사용됩니다. 예를 들어, true/false 값을 Yes/No 문자열로 변환하거나 Visibility로 변환하는 등의 작업을 수행할 수 있습니다.
<!-- Boolean 값을 "Yes" 또는 "No"로 변환하는 예시 -->
<Window.Resources>
<local:BooleanToYesNoConverter x:Key="BooleanToYesNoConverter" />
</Window.Resources>
<TextBlock Text="{Binding IsEnabled, Converter={StaticResource BooleanToYesNoConverter}}" />
public class BooleanToYesNoConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool boolValue)
{
return boolValue ? "Yes" : "No";
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
<!-- Boolean 값을 컨트롤의 가시성을 뜻하는 Visibility 속성으로 변환하는 예시 -->
<Window.Resources>
<local:VisibilityConverter x:Key="VisibilityConverter" />
</Window.Resources>
<Grid>
<TextBlock Text="Hello, World!" Visibility="{Binding IsVisible, Converter={StaticResource VisibilityConverter}}" />
</Grid>
public class VisibilityConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is bool boolValue)
{
return boolValue ? Visibility.Visible : Visibility.Collapsed;
}
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Visibility visibilityValue)
{
return visibilityValue == Visibility.Visible;
}
return Binding.DoNothing;
}
}
2. StringConverter
문자열을 다른 형식으로 변환하는 데 사용됩니다. 예를 들어, 숫자를 문자열로 변환하거나, 문자열의 대소문자를 변경하는 등의 작업을 수행할 수 있습니다.
<!-- 숫자를 문자열로 변환하는 예시 -->
<TextBlock Text="{Binding Quantity, Converter={StaticResource NumberToStringConverter}}" />
public class NumberToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is int intValue)
{
return intValue.ToString();
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
3. DateTimeConverter
날짜와 시간을 다른 형식으로 변환하는 데 사용됩니다. 예를 들어, 날짜 형식을 변경하거나, 날짜와 시간 사이의 차이를 계산하는 등의 작업을 수행할 수 있습니다.
<!-- 날짜 형식을 변경하는 예시 -->
<TextBlock Text="{Binding BirthDate, Converter={StaticResource DateTimeFormatConverter}, ConverterParameter='yyyy-MM-dd'}" />
public class DateTimeFormatConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is DateTime dateValue && parameter is string format)
{
return dateValue.ToString(format);
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
4. EnumConverter
열거형 값을 다른 형식으로 변환하는 데 사용됩니다. 예를 들어, 열거형 값을 문자열로 변환하거나, 문자열을 열거형 값으로 변환하는 등의 작업을 수행할 수 있습니다.
<!-- 열거형 값을 문자열로 변환하는 예시 -->
<TextBlock Text="{Binding Status, Converter={StaticResource EnumToStringConverter}}" />
public class EnumToStringConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is Enum enumValue)
{
return enumValue.ToString();
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
5. ColorConverter
색상을 다른 형식으로 변환하는 데 사용됩니다. 예를 들어, 색상을 RGB 값으로 변환하거나, RGB 값을 색상으로 변환하는 등의 작업을 수행할 수 있습니다.
<!-- SolidColorBrush를 Color로 변환하는 예시 -->
<TextBlock Foreground="{Binding StatusColor, Converter={StaticResource SolidColorBrushToColorConverter}}" />
public class SolidColorBrushToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is SolidColorBrush brush)
{
return brush.Color;
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
6. ValueConverter
값의 형식을 변환하는 데 사용됩니다. 이는 가장 일반적으로 사용되는 Converter입니다. 예를 들어, 숫자를 포맷팅하거나, 값의 범위를 제한하는 등의 작업을 수행할 수 있습니다.
<!-- 숫자를 포맷팅하는 예시 -->
<TextBlock Text="{Binding Price, Converter={StaticResource CurrencyConverter}}" />
public class CurrencyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is decimal decimalValue)
{
return decimalValue.ToString("C", culture); // 통화 형식으로 변환
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
7. MultiValueConverter
여러 개의 값을 변환하는 데 사용됩니다. 여러 데이터 소스의 값을 조합하여 하나의 값으로 변환할 수 있습니다. 예를 들어, 두 숫자를 합치거나, 여러 개의 속성을 결합하여 문자열을 생성하는 등의 작업을 수행할 수 있습니다.
<!-- 두 개의 값을 합치는 예시 -->
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource AdditionConverter}">
<Binding Path="Value1" />
<Binding Path="Value2" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
public class AdditionConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 2 && values[0] is double value1 && values[1] is double value2)
{
return value1 + value2;
}
return Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
8. DataTriggerConverter
데이터 바인딩 트리거에 사용되는 Converter입니다. 데이터 바인딩 값에 따라 UI 요소의 속성을 변경하는 데 사용됩니다. 예를 들어, 특정 조건에 따라 텍스트 색상을 변경하는 등의 작업을 수행할 수 있습니다.
<!-- 데이터 바인딩 값에 따라 텍스트 색상을 변경하는 예시 -->
<TextBlock Text="{Binding Status}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Black" />
<Style.Triggers>
<DataTrigger Binding="{Binding Status}" Value="Complete">
<Setter Property="Foreground" Value="Green" />
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="Pending">
<Setter Property="Foreground" Value="Orange" />
</DataTrigger>
<DataTrigger Binding="{Binding Status}" Value="Failed">
<Setter Property="Foreground" Value="Red" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
9. MultiBindingConverter
여러 개의 데이터 바인딩을 처리하는 데 사용되는 Converter입니다. 여러 데이터 소스의 값을 조합하여 하나의 값으로 변환할 수 있습니다. 예를 들어, 두 숫자를 곱하거나, 여러 개의 속성을 결합하여 문자열을 생성하는 등의 작업을 수행할 수 있습니다.
<!-- 두 값을 곱하는 예시 -->
<TextBlock>
<TextBlock.Text>
<MultiBinding Converter="{StaticResource MultiplicationConverter}">
<Binding Path="Value1" />
<Binding Path="Value2" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
public class MultiplicationConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Length == 2 && values[0] is double value1 && values[1] is double value2)
{
return value1 * value2;
}
return Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
10. ImageConverter
이미지를 다른 형식으로 변환하는 데 사용됩니다. 예를 들어, 이미지를 바이트 배열로 변환하거나, 바이트 배열을 이미지로 변환하는 등의 작업을 수행할 수 있습니다.
<!-- 이미지를 바이트 배열로 변환하는 예시 -->
<Window.Resources>
<local:ImageConverter x:Key="ImageConverter" />
</Window.Resources>
<Image Source="{Binding Image, Converter={StaticResource ImageConverter}}" />
using System;
using System.Globalization;
using System.IO;
using System.Windows.Data;
using System.Windows.Media.Imaging;
public class ImageConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// 입력 값이 BitmapImage인지 확인
if (value is BitmapImage image)
{
// 이미지를 메모리 스트림으로 변환하여 바이트 배열로 가져오기
using (MemoryStream memoryStream = new MemoryStream())
{
BitmapEncoder encoder = new PngBitmapEncoder(); // PNG 형식으로 인코딩
encoder.Frames.Add(BitmapFrame.Create(image)); // 이미지 프레임 추가
encoder.Save(memoryStream); // 스트림에 이미지 저장
return memoryStream.ToArray(); // 바이트 배열로 변환하여 반환
}
}
// 입력 값이 BitmapImage가 아닌 경우 Binding.DoNothing 반환
return Binding.DoNothing;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// 이 컨버터에서는 역변환을 지원하지 않으므로 NotSupportedException 발생
throw new NotSupportedException();
}
}
XAML에서 컨버터가 인식이 안 되는 경우
컨버터 클래스에 MarkupExtension을 추가로 상속하면 됩니다.
MarkupExtension
MarkupExtension은 XAML에서 사용되는 기능 중 하나로, XAML 마크업을 확장하고 커스터마이징하는 데 사용됩니다. MarkupExtension은 System.Windows.Markup 네임스페이스에 정의된 추상 클래스입니다.
MarkupExtension을 상속하는 클래스를 작성하여 사용자 정의 마크업 확장을 구현할 수 있습니다. 이 확장은 중괄호({}) 안에 특정 구문을 사용하여 XAML에서 값을 생성하거나 변환하는 작업을 수행할 수 있습니다. 예를 들어, 데이터 바인딩 설정, 리소스 참조, 다국어 지원 등 다양한 시나리오에서 MarkupExtension을 사용할 수 있습니다.
MarkupExtension을 상속한 클래스는 ProvideValue 메서드를 구현해야 합니다. 이 메서드는 XAML에서 확장을 사용할 때 호출되어 해당 확장이 반환해야 할 값을 제공합니다. ProvideValue 메서드에서는 필요한 로직을 수행하여 값을 생성하거나 변환할 수 있습니다.
사용자는 MarkupExtension을 상속하여 필요한 기능을 구현하고 XAML에서 사용할 수 있습니다. 이를 통해 XAML을 더 동적이고 유연하게 만들 수 있으며, 재사용 가능한 확장을 정의할 수 있습니다.
MarkupExtension 포함 코드 예시
일반적으로 컨버터를 XAML에서 사용하기 위해서는 컨버터 클래스가 IValueConverter 인터페이스를 구현하면 되지만, IValueConverter를 구현하는 단독 클래스는 XAML에서 직접적으로 인식되지 않을 수 있습니다. 이는 IValueConverter가 코드 레벨에서 작동하는 .NET Framework 구성 요소이기 때문입니다.
따라서 MarkupExtension를 상속하는 컨버터를 만들어 XAML에서 사용하면 XAML 런타임이 해당 컨버터를 인식하고 적절하게 처리할 수 있습니다.
예를 들어, ValueConverterExtension라는 MarkupExtension를 상속하는 클래스를 작성하고, 해당 클래스를 사용하여 컨버터를 XAML에서 사용할 수 있습니다. 예시는 다음과 같습니다.
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
public class ValueConverterExtension : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// 값을 변환하는 로직을 구현
// 예: 문자열을 대문자로 변환
if (value is string str)
{
return str.ToUpper();
}
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// 변환을 역으로 수행하는 로직을 구현
// 예: 대문자를 소문자로 변환
if (value is string str)
{
return str.ToLower();
}
return value;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this; // 확장 자체를 반환
}
}