0

GroupBox を含むフォームがあり、その中にいくつかのコントロール (チェックボックス、テキストボックス、およびコンボボックス) があります。

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

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

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

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

編集:

簡単な例 - これは Validation.Errors を表示しませんが、含まれている TextBox が失敗した場合、検証に失敗したとして 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);
    }
}
4

2 に答える 2

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();
    }
}

重要事項:

  • 'MyString' Binding の BindingGroupName をダミーの値に設定して、親の BindingGroup に含まれないようにします。
  • 「Checked1」および「Checked2」バインディングは、NotifyOnSourceUpdated を true に設定し、BindingGroup 検証を明示的に呼び出す必要がある Binding.SourceUpdated イベントにイベント ハンドラーを追加する必要があります。
  • BindingGroup.ValidateWithoutUpdate() が検証ロジックを実行できるように、BindingGroup の DataErrorValidationRule の ValidationStep は ConvertedProposedValue または RawProposedValue である必要があります。
于 2012-04-25T22:21:48.187 に答える
0

私はかつて同様の問題を抱えていましたが、これを回避する論理的な方法はないようです (パラドクソンのようなものを引き起こすため)。

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

于 2012-04-24T12:12:01.700 に答える