CHashtag

[C# WPF] Binding 값 자동 변환 Converter (IValueConverter, IMultiValueConverter) 본문

C#/WPF

[C# WPF] Binding 값 자동 변환 Converter (IValueConverter, IMultiValueConverter)

HyoSeong 2021. 2. 23. 01:51
반응형

WPF 프로그래밍 중 바인딩될 값에 따라 다른 값을 지정해 주어야 할 때가 종종 있습니다.

(예를 들면 입력받은 text가 10자 이상이면 background color가 변한다. 같은 느낌으로요.)

(Binding StringFormat의 상위 호환이라고 생각하시면 편할 것 같습니다.)

 

이럴 때 사용할 수 있는 것이 바로 IValueConverter, IMultiValueConverter입니다.

 

이해를 돕기위해 예제 프로그램을 제작해 보도록 하겠습니다.

 

Converter


Binding이 기본적으로 2 way를 지원하듯, Converter도 2 way converting을 지원합니다.

 

ViewModel -> View로 가는 Convert 함수와 View -> ViewModel로 가는 ConverterBack 함수를 IValueConverter가 지원합니다.

 

(IMultiValueConverter의 경우에도 인자가 다른 동일 함수를 제공합니다.)

 

 

IValueConverter


 

[Convert] 코로나 극복을 기원하며 사람 수를 입력받아 5명 이상일 경우 배경화면이 붉게 변하는 프로그램을 제작해 보도록 하겠습니다.

 

// IntToColorConverter.cs
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;

namespace WPF_Converter
{
    public class IntToColorConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            SolidColorBrush color = new SolidColorBrush(Colors.Transparent);
            if(value == null)
            {
                return color;
            }
            int personCount = (int)value;

            // 5인 이상 집합 금지!
            if (personCount >= 5)
            {
                color = new SolidColorBrush(Colors.Red);
            }
             
            return color;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

 

<!-- MainWindow.xaml -->
<Window x:Class="WPF_Converter.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:WPF_Converter"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="400">
    <Window.Resources>
        <local:IntToColorConverter x:Key="IntToColorConverter"/>
    </Window.Resources>
    <Grid Background="{Binding PersonCount, Converter={StaticResource IntToColorConverter}}">
        <TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Width="80" Height="50" FontSize="25" Text="{Binding PersonCount, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>

 

// MainWindowViewModel.cs
using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace WPF_Converter
{
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        private int _personCount;
        public int PersonCount
        {
            get => _personCount;
            set
            {
                _personCount = value;
                NotifyPropertyChanged();
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged([CallerMemberName] string name = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
        }
    }
}

 

// MainWindow.xaml.cs
using System.Windows;

namespace WPF_Converter
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private MainWindowViewModel _viewModel;
        public MainWindow()
        {
            InitializeComponent();

            _viewModel = new MainWindowViewModel();
            this.DataContext = _viewModel;
        }
    }
}

 

Converter를 사용하여 string을 color로 변환하는 프로그램을 제작해 보았습니다.

 

 

 

이제 ConvertBack을 사용해 볼 차례입니다.

 

위 프로그램의 TextBox에 숫자가 아닌 값이 들어가면 0으로 바꿔주도록 하는 Converter를 제작하여 적용해 보도록 하겠습니다.

 

// StringToIntConverter.cs
using System;
using System.Globalization;
using System.Windows.Data;

namespace WPF_Converter
{
    public class StringToIntConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            // ViewModel ->  View의 경우 기본값 그대로 return 하도록 한다.
            return value;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            int result = 0;

            Int32.TryParse((string)value, out result);

            return result;
        }
    }
}

 

<!-- MainWindow.xaml -->
<Window x:Class="WPF_Converter.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:WPF_Converter"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="400">
    <Window.Resources>
        <local:IntToColorConverter x:Key="IntToColorConverter"/>
        <local:StringToIntConverter x:Key="StringToIntConverter"/>
    </Window.Resources>
    <Grid Background="{Binding PersonCount, Converter={StaticResource IntToColorConverter}}">
        <TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Width="80" Height="50" FontSize="25" Text="{Binding PersonCount, Converter={StaticResource StringToIntConverter}, UpdateSourceTrigger=PropertyChanged}"/>
    </Grid>
</Window>

실행 결과는 다음과 같습니다.

5명 이하일 때에는 흰색이다.

 

하지만 5명 이상일 경우 빨간색으로 변한다.

 

IMultiValueConverter


IMultiValueConverter는 동작 구조는 기존의 IValueConverter와 동일합니다.

 

다만 차이점은 함수의 첫번째 인자인 value가 object[] values로 변한다는 점뿐입니다.

 

IMultiValueConverter 실습을 위해 현재 2단계 거리두기인지에 대한 값을 입력받는 CheckBox를 이용하여 2단계 이상일 때에만 5명 이상 모일 수 없도록 프로그램을 변경해보도록 하겠습니다.

 

<!-- MainWindow.xaml -->
<Window x:Class="WPF_Converter.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:WPF_Converter"
        mc:Ignorable="d"
        Title="MainWindow" Height="200" Width="400">
    <Window.Resources>
        <local:IntToColorConverter x:Key="IntToColorConverter"/>
        <local:IntAndBoolToColorConverter x:Key="IntAndBoolToColorConverter"/>
        <local:StringToIntConverter x:Key="StringToIntConverter"/>
    </Window.Resources>
    <Grid>
        <Grid.Background>
            <MultiBinding Converter="{StaticResource IntAndBoolToColorConverter}" >
                <Binding Path="PersonCount"/>
                <Binding Path="CheckBoxIsChecked"/>
            </MultiBinding>
        </Grid.Background>
        <StackPanel Orientation="Horizontal">
            <CheckBox Content="거리두기 2단계" VerticalAlignment="Center" IsChecked="{Binding CheckBoxIsChecked}"/>
            <TextBox HorizontalAlignment="Center" VerticalAlignment="Center" Width="80" Height="50" FontSize="25" Text="{Binding PersonCount, Converter={StaticResource StringToIntConverter}, UpdateSourceTrigger=PropertyChanged}"/>
        </StackPanel>
    </Grid>
</Window>

 

// MainViewModel.cs

private bool _checkBoxIsChecked;
public bool CheckBoxIsChecked
{
    get => _checkBoxIsChecked;
    set
    {
        _checkBoxIsChecked = value;
        NotifyPropertyChanged();
    }
}

 

// IntAndBoolToColorConverter.cs
using System;
using System.Globalization;
using System.Windows.Data;
using System.Windows.Media;

namespace WPF_Converter
{
    public class IntAndBoolToColorConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            SolidColorBrush color = new SolidColorBrush(Colors.Transparent);

            if (values == null)
            {
                return color;
            }

            int personCount = (int)values[0];

            bool isSecond = (bool)values[1];

            // 거리두기 2단계 이상일 때에는 5인 이상 집합 금지!
            if (isSecond && personCount >= 5)
            {
                color = new SolidColorBrush(Colors.Red);
            }

            return color;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

실행결과는 다음과 같습니다.

 

거리두기 2단계가 아닐 때에는 5인 이상 집합 가능.
하지만 거리두기 2단계일 경우 5인이상 집합 금지!

 

전체 코드는 아래 링크에서 확인하실 수 있습니다.

https://github.com/Hyo-Seong/CHashtag/tree/master/WPF_Converter

 

Hyo-Seong/CHashtag

https://chashtag.tistory.com/. Contribute to Hyo-Seong/CHashtag development by creating an account on GitHub.

github.com

 

 

 

나중에 이 게시글을 보며 그땐 그랬었지 하며 웃을 수 있는 날이 왔으면 좋겠습니다.

모두들 파이팅입니다.

 

감사합니다.

반응형