2012-04-19 10 views
0

私はGroupBoxを持つフォームを持っており、その中にいくつかのコントロール(チェックボックス、テキストボックス、およびコンボボックス)があります。WPF/XAML - 検証エラーが2回表示される

IDataErrorInfoプロパティを実装するビューモデルにフォームがバインドされています。ユーザーが無効な値をコントロールに入力すると、IDataInfoは無効な結果を返し、コントロールは通常の赤いボックスで囲まれます。エラーメッセージがフォームの下部に表示されます。

問題は、GroupBoxは必須の値のセットを示すことを意図していることです。ユーザは、グループ内のチェックボックスの少なくとも1つをチェックする必要があります。そうしないと、個々のコントロールでエラーになることはありません。グループにはエラーがあります。そこでGroupBoxにBindingGroupを追加し、何も選択されていなければエラーを返すValidationRuleを追加しました。そしてそれはうまく動作します。何も選択されていない場合、GroupBoxは通常の赤いボックスで囲まれ、フォームの下部にエラーメッセージが表示されます。

私の問題は、GroupBoxのコントロールの1つが検証に失敗すると、コントロールの周りに1つ、GroupBoxの周りに1つの赤いボックスが2つあることです。フォームの下部にあるリストに2つのエラーメッセージが表示されます。

グループに含まれるすべてのエラーをBindingGroupが報告しないようにするにはどうすればよいですか?

EDITED:

簡単な例 - これはValidation.Errorsは表示されませんが、あなたはStackPanelのが含まれているテキストボックスがない場合、検証に失敗したものとして強調されていることがわかります。

XAML:

<Window 
     x:Class="BugHunt5.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:BugHunt5" 
     Title="MainWindow" 
     Height="350" 
     Width="525" 
     > 
    <GroupBox 
      Margin="20" 
      Header="This is my group" 
      x:Name="MyGroupBox" 
      > 
     <StackPanel> 
      <StackPanel.BindingGroup> 
       <BindingGroup NotifyOnValidationError="True"> 
       </BindingGroup> 
      </StackPanel.BindingGroup> 
      <TextBox 
        Height="30" 
        Width="100" 
        > 
       <TextBox.Text> 
        <Binding 
          NotifyOnValidationError="True" 
          ValidatesOnDataErrors="True" 
          Path="MyString" 
          UpdateSourceTrigger="PropertyChanged" 
          > 
         <Binding.ValidationRules> 
          <local:NoDecimalsValidationRule ValidatesOnTargetUpdated="True"/> 
         </Binding.ValidationRules> 
        </Binding> 
       </TextBox.Text> 
      </TextBox> 
     </StackPanel> 
    </GroupBox> 
</Window> 

C#の:私は一度、同様の問題があったが、それはのようなものを引き起こすので、この(のうちの何の論理的な方法があるようでなかっまし

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 

     this.DataContext = new ViewModel("This should be an integer"); 
    } 
} 
public class ViewModel 
{ 
    public string MyString 
    { get; set; } 
    public ViewModel(string mystring) 
    { this.MyString = mystring; } 
} 
public class NoDecimalsValidationRule : ValidationRule 
{ 
    public override ValidationResult Validate(object value, 
     System.Globalization.CultureInfo cultureInfo) 
    { 
     string myString = value as string; 
     int result; 
     if (!Int32.TryParse(myString, out result)) 
      return new ValidationResult(false, "Must enter integer"); 
     return new ValidationResult(true, null); 
    } 
} 
+1

関連するxamlとコードを追加できますか? –

答えて

1

ViewModel.cs

public class ViewModel : INotifyPropertyChanged, IDataErrorInfo 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 

    private bool checked1, checked2; 
    private string myString; 

    public bool Checked1 
    { 
     get { return this.checked1; } 
     set { this.SetValue(ref this.checked1, value, "Checked1"); } 
    } 

    public bool Checked2 
    { 
     get { return this.checked2; } 
     set { this.SetValue(ref this.checked2, value, "Checked2"); } 
    } 

    public string MyString 
    { 
     get { return this.myString; } 
     set { this.SetValue(ref this.myString, value, "MyString"); } 
    } 

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     var handler = this.PropertyChanged; 
     if (handler != null) 
      handler(this, e); 
    } 

    private void SetValue<T>(ref T field, T value, string propertyName) 
    { 
     if (!EqualityComparer<T>.Default.Equals(field, value)) 
     { 
      field = value; 
      this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    public string Error 
    { 
     get 
     { 
      return this.checked1 == false && this.checked2 == false ? "Must check one value." : string.Empty; 
     } 
    } 

    string IDataErrorInfo.this[string propertyName] 
    { 
     get 
     { 
      switch (propertyName) 
      { 
       case "MyString": 
        int result; 
        return int.TryParse(this.myString, out result) ? string.Empty : "Must enter integer."; 
       default: 
        return string.Empty; 
      } 
     } 
    } 
} 

MainWindow.xaml

<Window x:Class="WpfApplication.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:local="clr-namespace:WpfApplication" 
     Title="MainWindow" Height="350" Width="525"> 
    <GroupBox Header="This is my group"> 
     <GroupBox.DataContext> 
      <local:ViewModel MyString="This should be an integer"/> 
     </GroupBox.DataContext> 
     <StackPanel> 
      <StackPanel.BindingGroup> 
       <BindingGroup x:Name="checkedBindingGroup"> 
        <BindingGroup.ValidationRules> 
         <DataErrorValidationRule ValidationStep="ConvertedProposedValue"/> 
        </BindingGroup.ValidationRules> 
       </BindingGroup> 
      </StackPanel.BindingGroup> 
      <CheckBox IsChecked="{Binding Checked1, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" Binding.SourceUpdated="OnCheckedSourceUpdated" Content="Checked1"/> 
      <CheckBox IsChecked="{Binding Checked2, UpdateSourceTrigger=PropertyChanged, NotifyOnSourceUpdated=True}" Binding.SourceUpdated="OnCheckedSourceUpdated" Content="Checked2"/> 
      <TextBox Text="{Binding MyString, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True, BindingGroupName=Dummy}"/> 
     </StackPanel> 
    </GroupBox> 
</Window> 

MainWindow.xaml.cs

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void OnCheckedSourceUpdated(object sender, DataTransferEventArgs e) 
    { 
     this.checkedBindingGroup.ValidateWithoutUpdate(); 
    } 
} 

番目の鍵ings:

  • BindingGroupNameをMyStringバインディングに設定するとダミー値に設定されるため、親BindingGroupには含まれません。
  • 'Checked1'と 'Checked2' Bindingsは、NotifyOnSourceUpdatedをtrueに設定し、BindingGroup検証を明示的に呼び出す必要があるBinding.SourceUpdatedイベントにイベントハンドラを追加する必要があります。
  • BindingGroup.ValidateWithoutUpdate()が検証ロジックを実行するように、BindingGroupのDataErrorValidationRuleのValidationStepはConvertedProposedValueまたはRawProposedValueである必要があります。
+0

それは動作します。ありがとう。 –

+0

さて、それはほとんど動作します。 ViewModel.Checked1またはViewModel.Checked2を変更すると、ウィンドウ内のCheckBoxコントロールが更新されますが、GroupBoxは再検証されません。 OnCheckedSourceUpdated()は起動しません。 –

+0

NotifyOnTargetUpdated = 'Checked's Bindings'にTrueを、Binding.TargetUpdated = "OnCheckedSourceUpdated"をチェックボックスに追加します。 – Stipo

0

パラドクソン)。

赤いアウトラインを削除するために、グループに関連付けられているチェックボックスまたはパネルの添付プロパティValidation.ErrorTemplateを使用すると、やることができます。

+0

StackPanelにStackPanelに接続されているValidationRulesの検証エラーを表示するようにします。 TextBoxのValidationRulesの検証エラーをTextBoxに表示させたい。私は、検証エラーが処理されるまで上向きに伝播したいと思っています。私が望まないのは、検証エラーが処理された後も引き続き伝播することです。 –

関連する問題