닷넷/WPF

WPF Converter (컨버터, 값 변환기)

FreeBear 2023. 6. 9. 15:06
반응형

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; // 확장 자체를 반환
    }
}

 

반응형