티스토리 뷰

728x90

■ 목차

1. ValueConversionSample 들어가기

2. 프로그램 동작 및 구조

3. 세 가지 변환기 구현 방법

4. 뷰와 아발로니아 요소들

 

1. ValueConversionSample 들어가기

크로스플랫폼 닷넷 UI 프레임워크인 아바로니아 맛보기를 넘어서서 본격적인 활용에 들어가기 위한 학습 방법으로 필자는 예제 프로그램 리뷰를 하나씩 수행하기로 했다. 기술 자료가 넉넉하고, 비주얼스튜디오의 WPF 디자이너와 같은 도구가 있다면 넘어갈 수도 있는 문제겠지만 지금까지 접하지 않았던 새로운 도구와 친숙해지는 방법은 역시 예제를 통하는 것이 좋은 방법이 아닌가 싶다. 공식 예제 코드는 깃허브 https://github.com/AvaloniaUI/Avalonia.Samples 에서 받을 수 있다. 커뮤니티에서 발굴해 놓은 예제와 참조 프로젝트도 있는데 깃허브 https://github.com/AvaloniaCommunity/awesome-avalonia 에서 확인할 수 있다.

 

 

ValueConversionSample은 MVVM(Models, Views, View Models) 패턴으로 개발 시 뷰의 특정 항목 값을 변환해서 표시

할 경우 참조할만한 예제이다. 예를 들면 입력값의 연산 결과나 코드 값에 따른 문자열 출력, 문자열 입력에 따른 색상 출력 등을 들 수 있다. 예제는 입력 항목의 내용을 파라미터로 변환기에 전달하고 그 결과를 바인딩하는 방식이다. Avalonia.Data.Converters의 인터페이스를 구현하는 형태로 사용한다. 세 가지의 변환기와 함께 동작하는 한 가지 뷰모델은 Reactive UI 프레임워크의 ReactiveObject를 상속받아서 작성되었다.

 

2. 프로그램 동작 및 구조

 

IValueConverter 인터페이스를 구현하는 예제는 뷰모델과 바인딩한 값과 파라미터로 동작하는 단순한 변환기 구현에 사용한다. 뷰의 정적 자원으로 2를 파라미터로 전달하고 Number1을 값으로 변환기에 전달하여 파라미터와 값을 더한 결과를 Sum에 출력하게 된다.

 

 

IMultiValueConverter 인터페이스는 변환기로 여러 개의 값을 전달하는 경우에 사용한다. 예제에서는 선택한 연산자와 두 개의 값을 변환기로 전달하고 연산 결과를 출력한다.

 

 

FuncValueConverter 제네릭 클래스를 사용하는 방법은 내부적으로 IValueConverter 인터페이스를 사용한다. 예제에서는 입력한 텍스트가 색상으로 표현 가능한 경우 텍스트박스 내부에 위치한 원에 해당 색상을 적용한다. 텍스트가 색상 이름이나 #FFFFFF 식의 색상 표현이 아니면 내부를 칠하지 않은 원으로 표시한다.

 

 

프로젝트는 MVVM 패턴에서 별도의 모델 없이 한 개의 뷰모델 및 뷰와 Converter 폴더에 있는 세 가지의 변환기로 구성된 형태이다.  뷰모델은 텍스트 박스와 바인딩하는 속성들과 콤보박스의 내용을 제공하는 단순한 형태이다.

 

3. 세 가지 변환기 구현 방법

변환기 구현은 Avalonia.Data.Converters 패키지를 사용한다.

public class MathAddConverter : IValueConverter
{
  public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
  {
    return (decimal?)value + (decimal?)parameter;
  }

  public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
  {
    return (decimal?)value - (decimal?)parameter;
  }
}

 

IValueConverter 인터페이스를 구현하는 방법은 뷰모델에서 뷰로 가는 변환은 Convert를 반대는 ConvertBack을 구현하면 된다. 

 

public class MathMultiConverter : IMultiValueConverter
{
  public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
  {
    if (values.Count != 3)
    {
      Trace.WriteLine("Exactly three values expected");
      return BindingOperations.DoNothing;
    }
    string operation = values[0] as string ?? "+";
    decimal value1 = values[1] as decimal? ?? 0;
    decimal value2 = values[2] as decimal? ?? 0;

    switch (operation)
    {
      case "+":
        return value1 + value2;
      case "-":
        return value1 - value2;
      case "*":
        return value1 * value2;
      case "/":
        if (value2 == 0)
        {
          return new BindingNotification(new DivideByZeroException("Don't do this!"), BindingErrorType.Error);
        }
        return value1 / value2;
    }
    return new BindingNotification(new InvalidOperationException("Something went wrong"), BindingErrorType.Error);
  }
}

 

IMultiValueConverter 인터페이스는 변환기로 여러 개의 값을 전달하는 경우에 적절하며 뷰모델에서 뷰로 가는 변환을 수행하는 Conver만 구현하면 된다.

 

public static FuncValueConverter<string?, Brush?> StringToBrushConverter { get; } = 
    new FuncValueConverter<string?, Brush?>(s =>
    {
      Color color;
      if (Color.TryParse(s, out color) || Color.TryParse($"#{s}", out color))
      {
        return new SolidColorBrush(color);
      }
      return null;
    });

 

FuncValueConverter 제네릭 클래스를 사용하는 방법은 내부적으로 IValueConverter 인터페이스를 사용하며 뷰모델에서 뷰로 가는 간편한 단방향 변환기를 사용할 수 있게 해 준다.  

 

4. 뷰와 아발로니아 요소들

<TabControl>
  <TabItem Header="IValueConverter">
    <Grid ColumnDefinitions="Auto, *" RowDefinitions="Auto, Auto">
      <TextBlock Grid.Row="0" Grid.Column="0" Text="Number 1" />
      <NumericUpDown Grid.Row="0" Grid.Column="1" Value="{Binding Number1}" />
      <TextBlock Grid.Row="1" Grid.Column="0" Text="Sum" />
      <NumericUpDown Grid.Row="1" Grid.Column="1"
               Value="{Binding Number1, Converter={StaticResource MathAddConverter}, ConverterParameter={StaticResource MyConverterParameter}}" />
    </Grid>
  </TabItem>
  <TabItem Header="IMultiValueConverter">
    <Grid ColumnDefinitions="Auto, *" RowDefinitions="Auto, Auto, Auto, Auto">
      <TextBlock Grid.Row="0" Grid.Column="0" Text="Operator" />
      <ComboBox Grid.Row="0" Grid.Column="1"
            ItemsSource="{Binding AvailableMathOperators}"
            SelectedItem="{Binding Operator}" />
      <TextBlock Grid.Row="1" Grid.Column="0" Text="Number 1" />
      <NumericUpDown Grid.Row="1" Grid.Column="1" Value="{Binding Number1}" />
      <TextBlock Grid.Row="2" Grid.Column="0" Text="Number 2" />
      <NumericUpDown Grid.Row="2" Grid.Column="1" Value="{Binding Number2}" />
      <TextBlock Grid.Row="3" Grid.Column="0" Text="Result" />
      <NumericUpDown Grid.Row="3" Grid.Column="1" IsReadOnly="True">
        <NumericUpDown.Value>
          <MultiBinding Converter="{StaticResource MathMultiConverter}" Mode="OneWay">
            <Binding Path="Operator" />
            <Binding Path="Number1" />
            <Binding Path="Number2" />
          </MultiBinding>
        </NumericUpDown.Value>
      </NumericUpDown>
    </Grid>
  </TabItem>
  <TabItem Header="FuncValueConverter">
    <StackPanel Spacing="5">
      <TextBox Watermark="Type the color to parse (e.g.: red, green, blue, #FF112233)" >
        <TextBox.InnerLeftContent>
          <Ellipse Fill="{Binding $parent[TextBox].Text, Converter={x:Static conv:FuncValueConverters.StringToBrushConverter}}"
               Width="20" Height="20" StrokeThickness="1" Margin="2" Stroke="Gray"/>
        </TextBox.InnerLeftContent>
      </TextBox>
    </StackPanel>
  </TabItem>
</TabControl>

 

728x90
댓글
최근에 올라온 글
최근에 달린 댓글
«   2026/01   »
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31
글 보관함