11

以前は非常に簡単だと思っていたことを実行しようとしています。あるコントロールの値を別のコントロールの検証ルールで使用します。私のアプリケーションには、ユーザーが入力できるさまざまなパラメーターがあります。ここで問題となっている特定のパラメーターは、範囲の開始点と終了点を定義し、ユーザーはテキスト ボックスを介して値を設定します。

問題の 2 つのコントロールは開始テキスト ボックスと終了テキスト ボックスであり、検証では次の条件をチェックする必要があります。

  1. 開始値は任意の値以上である必要があります
  2. 終了値は任意の値以下でなければなりません
  3. 開始値は終了値以下でなければなりません

最初の 2 つの条件は既に達成しています。バリデーターから最後のテキストボックスの値にアクセスできないため、3 番目の実装ははるかに困難です。できたとしても、検証しようとしている 5 つの異なる範囲 (それぞれに独自の開始テキスト ボックスと終了テキスト ボックスがあります) があり、それぞれに検証ルールを作成するよりも洗練されたソリューションが必要です。

関連する XAML コードは次のとおりです。

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:validators="clr-namespace:CustomValidators"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <TextBox Name="textboxStart" Grid.Row="0">
        <TextBox.Text>
            <Binding Path="Start" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <validators:MeasurementRangeRule Min="1513" Max="1583"/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>

    <TextBox Name="textboxEnd" Grid.Row="1">
        <TextBox.Text>
            <Binding Path="End" UpdateSourceTrigger="PropertyChanged">
                <Binding.ValidationRules>
                    <validators:MeasurementRangeRule Min="1513" Max="1583"/>
                </Binding.ValidationRules>
            </Binding>
        </TextBox.Text>
    </TextBox>
</Grid>

関連する C# コードは次のとおりです。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.CompilerServices;
using System.ComponentModel;
using System.Globalization;

namespace WpfApplication1 {
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window {
        public MainWindow () {
            InitializeComponent();
        }

        private decimal _start;
        private decimal _end;
        public event PropertyChangedEventHandler PropertyChanged;

        public decimal Start {
            get { return _start; }
            set {
                _start = value;
                RaisePropertyChanged();
            }
        }

        public decimal End {
            get { return _end; }
            set {
                _end = value;
                RaisePropertyChanged();
            }
        }

        private void RaisePropertyChanged ([CallerMemberName] string propertyName = "") {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

namespace CustomValidators {

    public class MeasurementRangeRule : ValidationRule {
        private decimal _min;
        private decimal _max;

        public decimal Min {
            get { return _min; }
            set { _min = value; }
        }

        public decimal Max {
            get { return _max; }
            set { _max = value; }
        }

        public override ValidationResult Validate (object value, CultureInfo cultureInfo) {
            decimal measurementParameter = 0;

            try {
                if (((string) value).Length > 0)
                    measurementParameter = Decimal.Parse((String) value);
            } catch (Exception e) {
                return new ValidationResult(false, "Illegal characters or " + e.Message);
            }

            if ((measurementParameter < Min) || (measurementParameter > Max)) {
                return new ValidationResult(false,
                  "Out of range. Enter a parameter in the range: " + Min + " - " + Max + ".");
            } else {
                return new ValidationResult(true, null);
            }
        }
    }
}

ここにリンクされている質問は関連しているようですが、提供された回答を理解できません。

ありがとう...

4

1 に答える 1

6

この問題に直面する可能性がある人にとっては、IDataErrorInfo を実装して一般的なエラーを検証し、論理グループ内の他のコントロールに対して検証を行う方がはるかに簡単です。関連するプロパティ (開始、終了、最小、最大) を 1 つのクラスにカプセル化し、コントロールをそれらのプロパティにバインドしてから、検証に IDataErrorInfo インターフェイスを使用しました。関連するコードは以下のとおりです...

XAML:

    <TextBox Name="textboxStart" Grid.Row="0" Text="{Binding Path=Start, ValidatesOnDataErrors=True}" Margin="5"/>
    <TextBox Name="textboxEnd" Grid.Row="1" Text="{Binding Path=End, ValidatesOnDataErrors=True}" Margin="5"/>
</Grid>

C#:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Runtime.CompilerServices;
using System.ComponentModel;

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

            Parameter testParameter = new Parameter(0, 10);
            testGrid.DataContext = testParameter;
        }
    }

    public class Parameter: INotifyPropertyChanged, IDataErrorInfo {
        private decimal _start, _end, _min, _max;
        public event PropertyChangedEventHandler PropertyChanged;

        public Parameter () { }

        public Parameter (decimal min, decimal max) {
            this.Min = min;
            this.Max = max;
        }

        public decimal Start {
            get { return _start; }
            set {
                _start = value;
                //RaisePropertyChanged for both Start and End, because one may need to be marked as invalid because of the other's current setting.
                //e.g. Start > End, in which case both properties are now invalid according to the established conditions, but only the most recently changed property will be validated
                RaisePropertyChanged();
                RaisePropertyChanged("End");
            }
        }

        public decimal End {
            get { return _end; }
            set {
                _end = value;
                //RaisePropertyChanged for both Start and End, because one may need to be marked as invalid because of the other's current setting.
                //e.g. Start > End, in which case both properties are now invalid according to the established conditions, but only the most recently changed property will be validated
                RaisePropertyChanged();
                RaisePropertyChanged("Start");
            }
        }

        public decimal Min {
            get { return _min; }
            set { _min = value; }
        }

        public decimal Max {
            get { return _max; }
            set { _max = value; }
        }

        private void RaisePropertyChanged ([CallerMemberName] string propertyName = "") {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public string Error {
            get { return string.Empty; }
        }

        public string this[string columnName] {
            get {
                string result = string.Empty;

                switch (columnName) {
                    case "Start":
                        if (Start < Min || Start > Max || Start > End) {
                            result = "Out of range. Enter a value in the range: " + Min + " - " + End + ".";
                        }
                        break;
                    case "End":
                        if (End < Min || End > Max || End < Start) {
                            result = "Out of range. Enter a value in the range: " + Start + " - " + Max + ".";
                        }
                        break;
                };

                return result;
            }
        }
    }
}
于 2013-09-03T06:13:36.720 に答える