5

最近まで、私はIDataErrorInfoインターフェースのカスタム拡張バージョンを使用していました。私の拡張機能を使用すると、複数のエラーを同時に処理できます。これまでのところ、非常にうまく機能しています。しかし、INotifyDataErrorInfoインターフェースが導入されたので、何か改善点があるかどうか試してみようと思いました。

いくつかのオンライン チュートリアルに従った後ValidationAttributeSystem.ComponentModel.DataAnnotations namespace. これらAttributeの を使用すると、次のような基本的な検証ルールを提供できます。

[MinLength(3, ErrorMessage = "Name must be longer than 3 characters.")]
public string Name
{
    get { return name; }
    set { name = value; NotifyPropertyChanged("Name"); Validate("Name", name); }
}

Valaidation.Errorsエラーメッセージは、適用された s で利用可能なコレクションに直接プラグインされるため、最初はかなり良いように見えましたErrorTemplate。ただし、組み込みの検証ルールのほとんどは本当に基本的なものであり、他のプロパティ値を含む複雑な検証ルールを実装する必要があることに慣れています。

そこで、複数のプロパティを含む単純な検証ルールを作成する方法を見つけようと試みました。これは、2 つ以上のフィールドのいずれかを設定する必要があるというルールです。そこで、 を拡張するクラスを宣言し、ValidationAttributeオンラインで検索した後、他のプロパティ値にアクセスする方法を見つけました。

各 にカスタムErrorTemplateを適用して基本的な UI を作成し、データ バインド プロパティTextBoxのコレクションを表示しました。Validation.Errors

<ControlTemplate x:Key="ErrorTemplate">
    <StackPanel Orientation="Horizontal">
        <Border BorderBrush="#4FFF0000" BorderThickness="1" Margin="0,10">
            <AdornedElementPlaceholder />
        </Border>
        <Image Name="WarningImage" Source="pack://application:,,,/WpfApplication1;component/Images/Warning_16.png" Margin="5,0,0,0" Tag="{Binding}" />
        <Popup PlacementTarget="{Binding ElementName=WarningImage}" Placement="Right" Margin="5,0,0,0" AllowsTransparency="True" IsOpen="True">
            <Border BorderThickness="1" BorderBrush="#4FFF0000" CornerRadius="5" Background="White" Padding="5" Margin="10">
                <Border.Effect>
                    <DropShadowEffect Color="Red" Opacity="0.5" BlurRadius="15" ShadowDepth="0" />
                </Border.Effect>
                <ItemsControl ItemsSource="{Binding}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding ErrorContent}" />
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Border>
        </Popup>
    </StackPanel>
</ControlTemplate>

プロパティのカスタムAttributeセットを使用して、どちらのプロパティも設定されていないときにインターフェイスを介してコレクションNameに を追加することができましたが、ここに問題があります。他の必要なプロパティにバインドされた他の es データのいずれかに値を追加した場合、最初のエラーメッセージはそこに残ります。ValidationResultValidation.ErrorsTextBoxTextBox

最初に戻ってTextBox何かを入力すると、検証が機能するため、値を削除しても、必要なプロパティの 1 つが設定されていることがわかりました。したがって、検証コードは機能しますが、問題は、他の必要なプロパティへのプロパティの変更がプロパティの検証をトリガーしないことNameです。

同じカスタムAttributeを他の必須プロパティに適用した場合でも、同じことが起こりました...各検証エラーは、関連するTextBox. CustomValidationAttributeクラス内のメソッドを呼び出して検証できるようにする組み込みも試しましたが、最終結果は同じでした。

検証コードは機能しますが、他の必要なプロパティの変更によってトリガーされません。他のプロパティの名前を渡してメソッドを呼び出してみValidateましたが、それは連続ループで終了しました。問題は、別のプロパティが検証されたときに、あるプロパティで検証をトリガーするにはどうすればよいかということです。

4

1 に答える 1

2

FromToプロパティを含むクラスで私がしたことは次のとおりです。Fromが以下であることを検証したかったのToです。

検証ロジックは を使用して適用されCustomValidationAttributeます。これは、独自の検証属性クラスを作成するよりも簡単です。クラスのタイプと、検証ロジックを含む呼び出すメソッドの名前を指定するだけです (ただし、メソッドには特定の署名が必要です)。ここに私の関連コードがあります:-

    [CustomValidation(typeof(MyModel), "ValidateRange")]
    public double From
    {
        get
        {
            return _from;
        }
        set
        {
            if (_from != value)
            {
                _from = value;
                OnPropertyChanged("From");

                // Validate the other side
                ValidateProperty("To", _to);
            }
        }
    }

    [CustomValidation(typeof(MyModel), "ValidateRange")]
    public double To
    {
        get
        {
            return _to;
        }
        set
        {
            if (_to != value)
            {
                _to = value;
                OnPropertyChanged("To");

                // Validate the other side
                ValidateProperty("From", _from);
            }
        }
    }

    private static ValidationResult ValidateRange(ValidationContext validationContext)
    {
        var model = validationContext.ObjectInstance as MyModel;

        if (model.From > model.To)
        {
            return new ValidationResult("Invalid range");
        }

        return null;
    }

ご覧のとおり、最後の段落で述べたとおり、1 つのプロパティ セッターのコードは、「他の」プロパティの検証を強制します。検証コードがプロパティの 1 つを設定しようとしていて、Validate() などの別の呼び出しがトリガーされない限り、無限ループに陥る理由はありません。

于 2014-07-22T13:35:49.577 に答える