PrismWPFSample(6)コンバーター

Prismを使用したWPFアプリケーション開発で役に立つと思われる項目を一つのアプリケーションにまとめたものを作りました。今回は、コンバーターについて書いています。

動作環境:Win10, Visual Studio Community 2017, Prism V7.1.0.431, .NET4.5.2, Prism Template Pack, TraceListeners, WPFLocalizeExtension, OxyPlot

アプリの外観はこんな感じです。

f:id:feynman911:20190628181422j:plain
 
コンバーターは ViewModel のプロパティーを View にバインドする時に表示方法を変換するために使われる部品ですが、なるべく汎用的に作って使いまわすのが基本です。ソフトを書くたびにコンバータも書いていたのでは意味がないので。

右側の ViewModel と書かれているものが、ViewModel のプロパティーとダイレクトにバインドしたテキストボックス。
左側の View と書かれているところがコンバーターを介してバインドしたものとなります。
ポイントは右側と左側は同じという事です。
例えば、ロジック側ではメートル単位ですべて処理。
表示はご自由な単位でどうぞという事です。
ViewModel 側に単位変換したプロパティーを作ってしまうと、Viewの変更ごとにコードを変更しなくてはならなくなります。
その下は
ViewModel の ushortプロパティーをそのままバインドしたのが右側で10進表示。
左側が2進数表示、16進数表示されたものとなります。
最後のRB1~RB4のものは、ラジオボタンを使う為のコンバーターです。

ScaleConverter

プログラム上はメートル単位で扱っていたけれども、表示は別の単位でとか言う事になった時に使う為のコンバーターです。単位が違うプロパティーをViewModelに作るというのはよくありません。
単に定数を掛け算するだけでなく、摂氏と華氏も変換できるように足し算と掛け算を合わせた汎用的な形にしてあります。

    //Viewの数値に10を足し50倍して更に3を足す例
    //ConverterParameter=10.0,50.0,3.0

    [ValueConversion(typeof(double), typeof(double))]
    public class ScaleConverter : IValueConverter
    {
        /// <summary>
        /// Datasource(ViewModel)→ Target(View)
        /// 数値にp0を足してp1倍してp2を足す
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object Convert(object value,
                              Type targetType,
                              object parameter,
                              CultureInfo culture)
        {
            double result = 0.0;
            double.TryParse(value.ToString(), out double val);
            string sp = (string)parameter;
            String[] paras = sp.Split(',');
            double.TryParse(paras[0], out double p0);
            double.TryParse(paras[1], out double p1);
            double.TryParse(paras[2], out double p2);
            if (p1 != 0)
            {
                result = (val + p0) * p1 + p2;
            }
            else
            {
                result = 0;
            }
            return result;
        }

        /// <summary>
        /// Target(View)→ Datasource(ViewModel)
        /// 数値からp2を引いてP1分の1にしP0を引く
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object ConvertBack(object value,
                              Type targetType,
                              object parameter,
                              CultureInfo culture)
        {
            double result = 0.0;
            double.TryParse(value.ToString(), out double val);
            string sp = (string)parameter;
            String[] paras = sp.Split(',');
            double.TryParse(paras[0], out double p0);
            double.TryParse(paras[1], out double p1);
            double.TryParse(paras[2], out double p2);
            if(p1 != 0) result = (val - p2) / p1 - p0;
            return result;
        }
    }

ヤード表示のテキストボックスとのバインドは次のようになります。
f:id:feynman911:20190711194201j:plain

Ushort2Bit16Converter

ViewModel の ushort プロパティーを View に2進表示したい時のコンバーターです。

    [ValueConversion(typeof(ushort), typeof(string))]
    public class Ushort2Bit16Converter : IValueConverter
    {
        /// <summary>
        /// Datasource(ViewModel) → Target(View)
        /// 0A28 -> 0000 1010 0010 1000
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object Convert(object value, 
                              Type targetType, 
                              object parameter, 
                              CultureInfo culture)
        {
            string ret = System.Convert.ToString(
                                   (ushort)value, 2).PadLeft(16, '0');
            ret = ret.Insert(4, " ");
            ret = ret.Insert(9, " ");
            ret = ret.Insert(14, " ");
            return ret;
        }

        /// <summary>
        /// Target(View)→ Datasource(ViewModel)
        /// 0000 1010 0010 1000 -> 0A28
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object ConvertBack(object value, 
                              Type targetType, 
                              object parameter, 
                              CultureInfo culture)
        {
            string temp = Regex.Replace((string)value, @"[^0-1]", "");
            ushort ret = System.Convert.ToUInt16(temp, 2);
            return ret;
        }
    }

Ushort2HexConverter

ViewModel の ushort プロパティーを View にHex表示したい時のコンバーターです。
このコンバータでTextBoxに16進入力ができるようになります。

    [ValueConversion(typeof(ushort),typeof(string))]
    public class Ushort2HexConverter : IValueConverter
    {
        /// <summary>
        /// Datasource(ViewModel) → Target(View)
        /// ushort型数字を16進4桁文字に変換
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object Convert(object value, 
                              Type targetType, 
                              object parameter, 
                              CultureInfo culture)
        {
            return ((ushort)value).ToString("X4");
        }

        /// <summary>
        /// Target(View)→ Datasource(ViewModel)
        /// 16進4桁文字をushort型数字に変換
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object ConvertBack(object value, 
                              Type targetType, 
                              object parameter, 
                              CultureInfo culture)
        {
            ushort.TryParse((string)value, 
                                NumberStyles.HexNumber, 
                                CultureInfo.CurrentCulture, 
                                out ushort result);
            return result;
        }
    }

EnumRadioConverter

ラジオボタンのどれが選ばれているかをViewModel側で知るためのコンバーターは次のようになります。

    //ラジオボタン選択コンバーター
    //パラメーターとして自分の名前(RB0とか)を設定し、同じ変数にバインドする
    //    private EnumDefines.RBEnum myType;
    //    public EnumDefines.RBEnum MyType
    //    {
    //        get { return this.myType; }
    //        set
    //        {
    //            this.myType = value;
    //            RaisePropertyChanged("MyType");
    //       }
    //    }

    public class EnumRadioConverter : IValueConverter
    {
        /// <summary>
        /// Datasource(ViewModel) → Target(View)
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object Convert(object value, 
                             Type targetType, 
                             object parameter, 
                             CultureInfo culture)
        {

            string paramString = parameter as string;
            if (paramString == null)
            {
                return DependencyProperty.UnsetValue;
            }

            if (!Enum.IsDefined(value.GetType(), paramString))
            {
                return DependencyProperty.UnsetValue;
            }

            var paramParsed = Enum.Parse(value.GetType(), paramString);

            return (value.Equals(paramParsed));
        }

        /// <summary>
        /// Target(View)→ Datasource(ViewModel)
        /// </summary>
        /// <param name="value"></param>
        /// <param name="targetType"></param>
        /// <param name="parameter"></param>
        /// <param name="culture"></param>
        /// <returns></returns>
        public object ConvertBack(object value, 
                             Type targetType, 
                             object parameter, 
                             CultureInfo culture)
        {
            var paramString = parameter as string;
            if (paramString == null)
            {
                return DependencyProperty.UnsetValue;
            }

            if ((bool)value != true) return DependencyProperty.UnsetValue;

            return Enum.Parse(targetType, paramString);
        }
    }
    public class EnumDefines
    {
        public enum RBEnum
        {
            RB0,
            RB1,
            RB2,
            RB3,
            RB4,
            RB5,
            RB6,
            RB7,
            RB8,
            RB9,
        }
    }

 
ラジオボタンのバインドはパラメータを使用して次のようになります。

f:id:feynman911:20190711204110j:plain


次回は、7. OxyPlot について記述したいと思います。