在单独的控件中显示验证文本

时间:2018-01-25 08:38:32

标签: c# wpf validation xaml

我有一个绑定到TextBox的属性,只允许为正数(即x > 0)。灵感来自this post我决定使用IDataErrorInfo接口实现此功能。

按照该帖子中的说明,如果输入无法验证,我可以获得工具提示警告。但我希望在输入TextBlock下方的单独TextBox中显示验证警告。

XAML:

<!-- ValidatingControl Style -->
<Style TargetType="{x:Type FrameworkElement}" x:Key="ValidatingControl">
    <Style.Triggers>
        <Trigger Property="Validation.HasError" Value="True">
            <Setter Property="ToolTip" Value="{Binding 
                Path=(Validation.Errors)[0].ErrorContent, 
                RelativeSource={x:Static RelativeSource.Self}}" />  
        </Trigger>
    </Style.Triggers>
</Style>

(...)

<TextBlock Text="Product price:" />
<TextBox
    Name="Price"
    DataContext="{Binding SelectedProduct}"
    Style="{StaticResource ValidatingControl}"
    Text="{Binding Path=Price, 
            StringFormat=N0, 
            ConverterCulture=da-DK, 
            Mode=TwoWay,
            ValidatesOnDataErrors=True}"/>

<!-- This should contain validation warning -->
<TextBlock Margin="0 0 0 10" />

绑定属性(C#):

public class ProductModel : IDataErrorInfo
{

    public decimal Price { get; set; }

    (...)

    // Implementation of IDataErrorInfo
    string IDataErrorInfo.Error
    {
        get { return null; }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get
    {
            if (columnName == "Price")
            {
                // Validate property and return a string if there is an error
                if (Price < 0)
                    return "Cannot be negative.";
            }

            // If there's no error, null gets returned
            return null;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

您可以将文本块绑定到IDataError接口索引器属性。

这里修改了代码

    <StackPanel>
        <TextBlock Text="Product price:" />
        <TextBox  Name="Price" Text="{Binding Path=Price, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay, ValidatesOnDataErrors=True}"/>

        <!-- This should contain validation warning -->
        <TextBlock Margin="0 0 0 10" Text="{Binding [Price]}" />
    </StackPanel>

您还需要对视图模型进行一些修改。

    class ViewModel : IDataErrorInfo, INotifyPropertyChanged
    {
        decimal _price;
        public decimal Price
        {
            get => _price;
            set
            {
                _price = value;
                RaisePropertyChanged(nameof(Price));
                RaisePropertyChanged("Item[]");
            }
        }

        // Implementation of IDataErrorInfo
        string IDataErrorInfo.Error
        {
            get { return null; }
        }

        public string this[string columnName]
        {
            get
            {
                if (columnName == "Price")
                {
                    // Validate property and return a string if there is an error
                    if (Price < 0)
                        return "Cannot be negative.";
                }

                // If there's no error, null gets returned
                return null;
            }
        }

        void RaisePropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

        public event PropertyChangedEventHandler PropertyChanged;
    }

注意,IDataErrorInfo接口的索引器属性是隐式实现的,否则WPF系统由于某种原因无法绑定到它。 另请参阅Price属性的INotifyPropertyChanged接口实现,尤其是RaisePropertyChanged("Item[]");行。没有这一行,如果出现错误,WPF的系统绑定系统将无法知道。

答案 1 :(得分:1)

您需要将索引器定义为 public 属性,实现INotifyPropertyChanged接口并在设置Price属性时为索引器引发更改通知。这应该有效:

public class ProductModel : IDataErrorInfo, INotifyPropertyChanged
{
    private decimal _price;
    public decimal Price
    {
        get { return _price; }
        set
        {
            _price = value;
            NotifyPropertyChanged();
            NotifyPropertyChanged("Item[]");
        }
    }

    string IDataErrorInfo.Error
    {
        get { return null; }
    }

    public string this[string columnName]
    {
        get
        {
            if (columnName == "Price")
            {
                // Validate property and return a string if there is an error
                if (Price < 0)
                    return "Cannot be negative.";
            }

            // If there's no error, null gets returned
            return null;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

<强> XAML:

<!-- This should contain validation warning -->
<TextBlock DataContext="{Binding SelectedProduct}" Margin="0 0 0 10" Text="{Binding [Price]}" />