web-dev-qa-db-ja.com

WPF検証ルールを使用して[保存]ボタンを無効にする

[保存]ボタンをクリックする前に、いくつかのテキストボックスを空にできないページがあります。

<TextBox...

                <TextBox.Text>
                    <Binding Path ="LastName" UpdateSourceTrigger="PropertyChanged">

                        <Binding.ValidationRules>
                            <local:StringRequiredValidationRule />
                        </Binding.ValidationRules>                              
                    </Binding>
                </TextBox.Text>

私のルールは機能します。値を入力するまで、テキストボックスの周りに赤い枠があります。そこで、この検証ルールを他のテキストボックスに追加します。

では、ページにエラーがなくなるまで[保存]ボタンを無効にするにはどうすればよいですか。検証エラーがあるかどうかを確認するために何をチェックすべきかわかりません。

27
ScottG
18
Developer

ビューの分離コードでは、Validation.ErrorEventを次のように結び付けることができます。

this.AddHandler(Validation.ErrorEvent,new RoutedEventHandler(OnErrorEvent)); 

その後

private int errorCount;
private void OnErrorEvent(object sender, RoutedEventArgs e)
{
    var validationEventArgs = e as ValidationErrorEventArgs;
    if (validationEventArgs  == null)
        throw new Exception("Unexpected event args");
    switch(validationEventArgs.Action)
    {
        case ValidationErrorEventAction.Added:
            {
                errorCount++; break;
            }
        case ValidationErrorEventAction.Removed:
            {
                errorCount--; break;
            }
        default:
            {
                throw new Exception("Unknown action");
            }
    }
    Save.IsEnabled = errorCount == 0;
}

これは、削除の通知を受け取ることを前提としています(無効な要素を削除した場合は発生しません)。

15
Christoph

Validation.HasError 添付プロパティを使用したい。

同じように、ジョシュ・スミスは Binding to(Validation.Errors)[0] without Createing Debug Spew について興味深い記事を読んでいます。

8
Todd White
int count = 0;

private void LayoutRoot_BindingValidationError(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
    {
        button1.IsEnabled = false;
        count++;
    }
    if (e.Action == ValidationErrorEventAction.Removed)
    {                
        count--;
        if (count == 0) button1.IsEnabled = true;
    }
}
3
Nihal

以下は、依存関係オブジェクト(およびそのすべての子)の検証エラーを追跡し、デリゲートを呼び出して変更について通知するヘルパーメソッドです。また、検証エラーのある子の削除も追跡します。

 public static void AddErrorHandler(DependencyObject element, Action<bool> setHasValidationErrors)
        {
            var errors = new List<Tuple<object, ValidationError>>();

            RoutedEventHandler sourceUnloaded = null;

            sourceUnloaded = (sender, args) =>
                {
                    if (sender is FrameworkElement)
                        ((FrameworkElement) sender).Unloaded -= sourceUnloaded;
                    else
                        ((FrameworkContentElement) sender).Unloaded -= sourceUnloaded;

                    foreach (var error in errors.Where(err => err.Item1 == sender).ToArray())
                        errors.Remove(error);

                    setHasValidationErrors(errors.Any());
                };

            EventHandler<ValidationErrorEventArgs> errorHandler = (_, args) =>
                {
                    if (args.Action == ValidationErrorEventAction.Added)
                    {
                        errors.Add(new Tuple<object, ValidationError>(args.OriginalSource, args.Error));

                        if (args.OriginalSource is FrameworkElement)
                            ((FrameworkElement)args.OriginalSource).Unloaded += sourceUnloaded;
                        else if (args.OriginalSource is FrameworkContentElement)
                            ((FrameworkContentElement)args.OriginalSource).Unloaded += sourceUnloaded;
                    }
                    else
                    {
                        var error = errors
                            .FirstOrDefault(err => err.Item1 == args.OriginalSource && err.Item2 == args.Error);

                        if (error != null) 
                            errors.Remove(error);
                    }

                    setHasValidationErrors(errors.Any());
                };


            System.Windows.Controls.Validation.AddErrorHandler(element, errorHandler);
        } 
2
andrey.tsykunov

これは、背後のコードからHasErrorコントロールプロパティを確認する必要があることです

保存ボタンをクリックしてこのコードを実行します

 BindingExpression bexp = this.TextBox1.GetBindingExpression(TextBox.TextProperty);
bexp.UpdateSource(); // this to refresh the binding and see if any error exist 
bool hasError = bexp.HasError;  // this is boolean property indique if there is error 

MessageBox.Show(hasError.ToString());
2
Bilal

上記の解決策のいくつかを試しました。しかし、どれも私のために働いていませんでした。

私の簡単な問題

ユーザーにURIを要求する単純な入力ウィンドウがあります。TextBox値が有効なUriでない場合、Okayボタンを無効にする必要があります。

私の簡単な解決策

これが私のために働いたものです:

CommandBindings.Add(new CommandBinding(AppCommands.Okay,
            (sender, args) => DialogResult = true,
            (sender, args) => args.CanExecute = !(bool) _uriTextBoxControl.GetValue(Validation.HasErrorProperty)));
1
Kabuo

validateのSystem.ComponentModel.IDataErrorInfoから、および通知ボタンのINotifyPropertyChangedからViewModelを継承するだけです

プロパティを作成:

    public bool IsValid
    {
        get
        {
            if (this.FloorPlanName.IsEmpty())
                return false;
            return true;
        }
    }

xAMLでボタンに接続します

<Button Margin="4,0,0,0" Style="{StaticResource McVMStdButton_Ok}" Click="btnDialogOk_Click" IsEnabled="{Binding IsValid}"/>

iDataErrorInfoオーバーライドで、btuttonに通知

public string this[string columnName]{
        get
        {
            switch (columnName)
            {
                case "FloorPlanName":
                    if (this.FloorPlanName.IsEmpty())
                    {
                        OnPropertyChanged("IsValid");
                        return "Floor plan name cant be empty";
                    }
                    break;
            }
        }
}
1

まだ足りないので、リンクが消えてしまった場合に備えて、開発者の回答を以下に示します。

XAML:

<TextBox.Text Validation.Error="handleValidationError">
    <Binding Path ="LastName" 
             UpdateSourceTrigger="PropertyChanged"
             NotifyOnValidationError="True">
        <Binding.ValidationRules>
            <local:StringRequiredValidationRule />
        </Binding.ValidationRules>                              
    </Binding>
</TextBox.Text>
<Button IsEnabled="{Binding HasNoValidationErrors}"/>

CodeBehind/C#:

private int _numberOfValidationErrors;
public bool HasNoValidationErrors => _numberOfValidationErrors = 0;

private void handleValidationError(object sender, ValidationErrorEventArgs e)
{
    if (e.Action == ValidationErrorEventAction.Added)
        _numberOfValidationErrors++;
    else
        _numberOfValidationErrors--;
}
0