none
1つBinding時に複数のコントロールに、ValidatesOnExceptionsを通知させたい。 RRS feed

  • 質問

  • いつも御世話になっております。

    Binding 時のValidationを利用して、TextBoxAとTextBoxBの、どちらかに値が入力されていないとエラーとし、双方の枠を赤くするといった処理を記述したいと考えています。また、逆にどちらかが入力されたら、枠の色を元に戻したいと考えています。

    下記のように記述してみたのですが、
    throw new ArgumentException() が、呼び出し元のコントロールに通知されるので、
    当然のことながら、呼び出し元でValidation Errorがあったと判定されるのみとなります。

     xaml

    <TextBox Text="{Binding Name1, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/>
    
    <TextBox Text="{Binding Name2, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True}"/>

    C#

            private string name1;
            public string Name1
            {
                get {
    
                    return name1;
                }
                set
                {
    
                    name = value;
                    check();
                    OnPropertyChanged("Name1");
                }
            }
    
            private string name2;
            public string Name2
            {
                get {
    
                    return name2;
                }
                set
                {
    
                    name = value;
                    check();
                    OnPropertyChanged("Name2");
                }
            }
    
    
            private void check()
            {
                 if(string.IsNullOrEmpty(name1) &&
                    string.IsNullOrEmpty(name2) ) {
                    throw new ArgumentException();
                 }
             }

    検討がつかず、質問をさせて頂きました。
    ご迷惑をおかけしますが、アドバイスいただけないでしょうか?
    宜しくお願い致します。
    2009年9月10日 7:55

回答

  • ValidatesOnExceptions は1フィールド用です。
    ValidatesOnDataErrorsを使ってください。

    <Window x:Class="Wpf2Binding.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
        <Grid.RowDefinitions>
          <RowDefinition />
          <RowDefinition />
          <RowDefinition />
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" Text="{Binding Name1, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True, ValidatesOnDataErrors=True }"/>
        <TextBox Grid.Row="1" Text="{Binding Name2, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True, ValidatesOnDataErrors=True}"/>
        <Button Grid.Row="2" Name="button1" Click="button1_Click">Button</Button>
      </Grid>
    </Window>
    


    /// <summary>
    /// Window1.xaml の相互作用ロジック
    /// </summary>
    public partial class Window1 : Window, INotifyPropertyChanged, IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();
    
        public Window1()
        {
            InitializeComponent();
            this.DataContext = this;
        }
        private string name1;
        public string Name1
        {
            get
            {
                return name1;
            }
            set
            {
                if (value != null && value.Length > 10)
                {
                    _errors["Name1"] = "Too big";
                }
                else
                {
                    _errors["Name1"] = null;
                }
                name1 = value;
                OnPropertyChanged("Name1");
                OnPropertyChanged("Name2");
            }
        }
    
        private string name2;
        public string Name2
        {
            get
            {
                return name2;
            }
            set
            {
                name2 = value;
                OnPropertyChanged("Name1");
                OnPropertyChanged("Name2");
            }
        }
    
    
        #region INotifyPropertyChanged メンバ
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string p)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this,new PropertyChangedEventArgs(p));
            }
        }
    
        #endregion
    
        #region IDataErrorInfo メンバ
    
        public string Error
        {
            get
            {
                if (string.IsNullOrEmpty(name1) &&
                   string.IsNullOrEmpty(name2))
                {
                    return "Empty!";
                }
                return null;
            }
        }
    
        public bool HasErrors
        {
            get { return (_errors.Count != 0 || Error != null); }
        }
    
        public string this[string columnName]
        {
            get 
            {
                if (_errors.ContainsKey(columnName))
                {
                    return _errors[columnName];
                }
                if (columnName == "Name1" || columnName == "Name2")
                {
                    if (string.IsNullOrEmpty(name1) &&
                       string.IsNullOrEmpty(name2))
                    {
                        return "Empty!";
                    }
                }
                return null;
            }
        }
    
        #endregion
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            if (this.HasErrors) return;
            // 正常時
        }
    }
    

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    • 回答としてマーク a_山田 2009年9月11日 2:34
    2009年9月10日 9:35

すべての返信

  • ValidatesOnExceptions は1フィールド用です。
    ValidatesOnDataErrorsを使ってください。

    <Window x:Class="Wpf2Binding.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="300" Width="300">
        <Grid>
        <Grid.RowDefinitions>
          <RowDefinition />
          <RowDefinition />
          <RowDefinition />
        </Grid.RowDefinitions>
        <TextBox Grid.Row="0" Text="{Binding Name1, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True, ValidatesOnDataErrors=True }"/>
        <TextBox Grid.Row="1" Text="{Binding Name2, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True, ValidatesOnDataErrors=True}"/>
        <Button Grid.Row="2" Name="button1" Click="button1_Click">Button</Button>
      </Grid>
    </Window>
    


    /// <summary>
    /// Window1.xaml の相互作用ロジック
    /// </summary>
    public partial class Window1 : Window, INotifyPropertyChanged, IDataErrorInfo
    {
        private Dictionary<string, string> _errors = new Dictionary<string, string>();
    
        public Window1()
        {
            InitializeComponent();
            this.DataContext = this;
        }
        private string name1;
        public string Name1
        {
            get
            {
                return name1;
            }
            set
            {
                if (value != null && value.Length > 10)
                {
                    _errors["Name1"] = "Too big";
                }
                else
                {
                    _errors["Name1"] = null;
                }
                name1 = value;
                OnPropertyChanged("Name1");
                OnPropertyChanged("Name2");
            }
        }
    
        private string name2;
        public string Name2
        {
            get
            {
                return name2;
            }
            set
            {
                name2 = value;
                OnPropertyChanged("Name1");
                OnPropertyChanged("Name2");
            }
        }
    
    
        #region INotifyPropertyChanged メンバ
    
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string p)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this,new PropertyChangedEventArgs(p));
            }
        }
    
        #endregion
    
        #region IDataErrorInfo メンバ
    
        public string Error
        {
            get
            {
                if (string.IsNullOrEmpty(name1) &&
                   string.IsNullOrEmpty(name2))
                {
                    return "Empty!";
                }
                return null;
            }
        }
    
        public bool HasErrors
        {
            get { return (_errors.Count != 0 || Error != null); }
        }
    
        public string this[string columnName]
        {
            get 
            {
                if (_errors.ContainsKey(columnName))
                {
                    return _errors[columnName];
                }
                if (columnName == "Name1" || columnName == "Name2")
                {
                    if (string.IsNullOrEmpty(name1) &&
                       string.IsNullOrEmpty(name2))
                    {
                        return "Empty!";
                    }
                }
                return null;
            }
        }
    
        #endregion
    
        private void button1_Click(object sender, RoutedEventArgs e)
        {
            if (this.HasErrors) return;
            // 正常時
        }
    }
    

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    • 回答としてマーク a_山田 2009年9月11日 2:34
    2009年9月10日 9:35
  • 現象は確認しました。
    仕様的なものかはわからないです。

    ここでバグとしてレポートしてほしいです。
    https://connect.microsoft.com/VisualStudioJapan


    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年9月10日 11:48
  • えムナウ様、ご回答ありがとうございました。

    本件の内容は少し違うかもしれませんが、一つ気になったことがございますので、
    質問させていただきます。

    頂きました例で、例えば、Name1に11以上入力したとします。
    その場合、赤い枠の状態(エラー状態)になります。
    その状態で、button1_Clickなどのイベントで、Gridの表示状態を、
    Visibility.hidden の状態にすると、TextBoxやButtonなどのコントールは消えるのですが、
    赤い枠だけが残ってしまいます。

    赤い枠が残るのは、正常な動作ということなのでしょうか?
    2009年9月10日 11:55
  • あれ、質問を書き直されたのですね。
    赤い枠が残ることは確認しました。

    仕様的なもので正常な動作かはわからないです。

    ここでバグとしてレポートしてほしいです。(日本語でOKです)
    ここでの答えで仕様的なもので正常な動作かどうかがわかります。
    https://connect.microsoft.com/VisualStudioJapan

    えムナウ@わんくま同盟 Microsoft MVP Visual Studio C# Since 2005/01-2009/12
    2009年9月10日 11:59
  • すいません、少し、文章におかしな箇所がありましたので、質問を書き直させていただきました。
    ご回答ありがとうございます。

    バグレポートさせて頂きます。

    また、上記のソースで、一部、修正させて頂きました。

    if (_errors.ContainsKey(columnName) && _errors[columnName] != null)
    {
          return _errors[columnName];
    }

    と、させて頂きました。

    誠にありがとうございました。

    2009年9月10日 12:23