3

私の WPF アプリケーションには次のシナリオがあります。

  1. ユーザーがテキスト ボックスに値を入力します。
  2. その値を検証するためにバックグラウンド スレッドを開始します (Web サービス呼び出しを介して)。
    (入力が有効な時間の 98%。)
  3. ユーザーはテキスト ボックスを離れ、次のテキスト ボックスの作業に向かいます。
  4. バックグラウンド スレッドが戻り、結果は入力が無効であることを示します。
    イベントの発生により、ビューモデルにこれを知らせます。(私は Prism のイベントとモジュールを使用しています。)

そのイベントが、指定された入力に検証エラーがあったことを TextBox に知らせる方法が必要です。(フォーカスがそのコントロールにないことに注意してください。)

「独自の検証をロールバック」してこれを完了するためのあらゆる種類の方法を考えることができます。しかし、WPF の既存の検証フレームワーク内で作業したいと考えています。

注: 関連性があるかどうかはわかりませんが、[保存] ボタンを有効にする前に、すべて合格する必要がある "NeededValidations" のリストを維持する必要があります。

4

1 に答える 1

6

IDataErrorInfoを使用して試すことができるいくつかのメソッドを次に示します。どちらも、INotifyPropertyChanged通知を発行すると、バインディング検証の再評価が発生するという事実に依存しています。

2つのテキストボックスがあります。1つは非同期バインディングを使用し、Webサービス呼び出しが同期していると想定します。2つ目は同期バインディングを使用し、Webサービス呼び出しが非同期であると想定しています。

Xaml

<Window.DataContext>
    <WpfValidationUpdate:ViewModel/>
</Window.DataContext>

<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>

    <TextBox Margin="5" Grid.Row="0" Text="{Binding Text1, IsAsync=True, ValidatesOnDataErrors=True}"/>
    <TextBox Margin="5" Grid.Row="1" Text="{Binding Text2, ValidatesOnDataErrors=True}"/>
</Grid>

モデルを見る

public class ViewModel : IDataErrorInfo, INotifyPropertyChanged
{
    private string _text1;
    private string _text2;
    private bool _text1ValidationError;
    private bool _text2ValidationError;

    #region Implementation of IDataErrorInfo

    public string this[string columnName]
    {
        get
        {
            if(columnName == "Text1" && _text1ValidationError)
            {
                return "error";
            }

            if(columnName == "Text2" && _text2ValidationError)
            {
                return "error";
            }

            return string.Empty;
        }
    }

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

    public string Text1
    {
        get { return _text1; }
        set
        {
            _text1 = value;
            OnPropertyChanged("Text1");

            // Simulate web service synchronously taking a long time
            // Relies on async binding
            Thread.Sleep(2000);
            _text1ValidationError = true;

            OnPropertyChanged("Text1");
        }
    }

    public string Text2
    {
        get { return _text2; }
        set
        {
            _text2 = value;
            OnPropertyChanged("Text2");

            // Simulate web service asynchronously taking a long time
            // Doesn't rely on async binding
            Task.Factory.StartNew(ValidateText2);
        }
    }

    private void ValidateText2()
    {

        Thread.Sleep(2000);

        _text2ValidationError = true;
        OnPropertyChanged("Text2");
    }

    #endregion

    #region Implementation of INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;

    private void OnPropertyChanged(string propertyName)
    {
        var handler = PropertyChanged;
        if(handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    #endregion
}
于 2012-05-01T19:43:15.367 に答える