Xamarin.Forms + ReactiveProperty로 ColorChooser 앱 만들기

할 일



이런 느낌으로 RGB 슬라이더를 움직이면 색이 바뀌는 같은 앱을 만들어 본다.
보통으로 만들면 NotifyPropertyChanged 를 구사해 값의 변화를 각 프로퍼티에 전파시킬 필요가 있다고 생각합니다만, ReactiveProperty



View (XAML + C#)


using System;
using System.Collections.Generic;
using ReactiveColorChooser.ViewModels;
using Xamarin.Forms;

namespace ReactiveColorChooser.Views
{
    public partial class ColorChooserPage : ContentPage
    {
        public ColorChooserPage()
        {
            InitializeComponent();

            Title = "Reactive Color Chooser";
            BindingContext = new ColorChooserViewModel();

            Red.SetBinding<ColorChooserViewModel>(Slider.ValueProperty, vm => vm.Red.Value);
            Green.SetBinding<ColorChooserViewModel>(Slider.ValueProperty, vm => vm.Green.Value);
            Blue.SetBinding<ColorChooserViewModel>(Slider.ValueProperty, vm => vm.Blue.Value);
            MixedColor.SetBinding<ColorChooserViewModel>(BoxView.BackgroundColorProperty, vm => vm.MixedColor.Value);
        }
    }
}

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="ReactiveColorChooser.Views.ColorChooserPage">
    <ContentPage.Content>
        <StackLayout Padding="10, 20">
            <StackLayout>
                <Label Text="{Binding IntRed.Value}" TextColor="Red" />
                <Slider x:Name="Red" Maximum="1" Minimum="0" Value="0" />
                <Label Text="{Binding IntGreen.Value}" TextColor="Green" />
                <Slider x:Name="Green" Maximum="1" Minimum="0" Value="0" />
                <Label Text="{Binding IntBlue.Value}" TextColor="Blue" />
                <Slider x:Name="Blue" Maximum="1" Minimum="0" Value="0" />
            </StackLayout>
            <StackLayout Orientation="Vertical" Padding="0, 20, 0, 0">
                <BoxView x:Name="MixedColor" />
                <Label Text="{Binding HexColor.Value}" TextColor="{Binding MixedColor.Value}" FontSize="20" />
            </StackLayout>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>
  • ContentPage에 BindingContext를 설정하면 XAML 측에서 Binding을 사용할 수 있습니다.
  • 코드측에서 ViewModel 의 값과 View 의 값을 SetBinding 로 묶어 줄 필요가 있다. 한편, SetBinding이 어긋나게 늘어선 것은, 조금 중복감도 있다.

  • ViewModel


    using System;
    using System.Reactive.Linq;
    using Reactive.Bindings;
    using Xamarin.Forms;
    
    namespace ReactiveColorChooser.ViewModels
    {
        public class ColorChooserViewModel
        {
            public ReactiveProperty<double> Red { get; private set; }
            public ReactiveProperty<int> IntRed { get; private set; }
    
            public ReactiveProperty<double> Green { get; private set; }
            public ReactiveProperty<int> IntGreen { get; private set; }
    
            public ReactiveProperty<double> Blue { get; private set; }
            public ReactiveProperty<int> IntBlue { get; private set; }
    
            public ReactiveProperty<Color> MixedColor { get; private set; }
            public ReactiveProperty<string> HexColor { get; private set; }
    
            public ColorChooserViewModel()
            {
                Red   = new ReactiveProperty<double>(0.0f);
                Green = new ReactiveProperty<double>(0.0f);
                Blue  = new ReactiveProperty<double>(0.0f);
    
               // スライダーの値を0 - 255の範囲の整数に変換
                IntRed = Observable.Select(Red, DoubleToInt).ToReactiveProperty();
                IntGreen = Observable.Select(Green, DoubleToInt).ToReactiveProperty();
                IntBlue = Observable.Select(Blue, DoubleToInt).ToReactiveProperty();
    
               // スライダーの値から色を生成
                MixedColor = Observable.CombineLatest(IntRed, IntGreen, IntBlue, (r, g, b) => Color.FromRgb(r, g, b)).ToReactiveProperty();
    
                // 現在の色を16進数表示
                HexColor = Observable.CombineLatest(IntRed, IntGreen, IntBlue, (r, g, b) => string.Format(@"#{0}{1}{2}", r.ToString("X2"), g.ToString("X2"), b.ToString("X2"))).ToReactiveProperty();
            }
    
            private int DoubleToInt(double x)
            {
                return (int)(x * 255);
            }
        }
    }
    
  • ReactiveProperty<T> 형태로 선언하는 것으로, 마음대로 값의 변화를 감시해 줍니다. 멋지다!
  • 값의 변화는 Observable에서 받고 처리하면 됩니다. 리액티브 감!
  • 처리 후에는 ToReactiveProperty 에서 ReactiveProperty 형식으로 되돌리는 것을 잊지 마세요.

  • 받은 값에 대해서는 여러가지 처리를 할 수 있으므로, 이쪽의 조견표를 참고로 하면서 쓰면 좋다고 생각합니다. 매우 도움을 주셔서 감사합니다.

    Reactive Extensions 재입문 번외편 「System.Reactive.Linq.Observable의 메소드 일람과 메모」

    C#의 초보자로는, 「제대로 변환되고 있는지 모르겠다ー」라고 할 때는 Do Ruby로 말한다 tap 같은 것 같네요.
    // 例: 値を変換するたびにログ表示
    IntRed = Observable.Select(Red, DoubleToInt).Do(x => System.Diagnostics.Debug.WriteLine(x)).ToReactiveProperty();
    

    후기



    리액티브, 좋아!

    참고 : MVVM을 리액티브 프로그래밍으로 편안하게 ReactiveProperty 오버뷰

    좋은 웹페이지 즐겨찾기