微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c# – 如何在WPF应用程序中显示错误消息?

我正在尝试使用 WPF创建一个应用程序.我正在尝试使用MVVM模型完全构建它.但是,我很困惑如何正确显示错误消息.我认为这将是微不足道的一步,但似乎是最复杂的.

我使用xaml创建了以下视图

<StackPanel Style="{StaticResource Col}">
    <DockPanel>
        <Grid DockPanel.Dock="Top">
            <Grid.ColumnDeFinitions >
                <ColumnDeFinition Width="*" ></ColumnDeFinition>
                <ColumnDeFinition Width="*"></ColumnDeFinition>
            </Grid.ColumnDeFinitions>
            <StackPanel Grid.Column="0" Style="{StaticResource Col}">
                <Label Content="Name" Style="{StaticResource Formlabel}" />
                <Border Style="{StaticResource FormInputBorder}">
                    <TextBox x:Name="Name" Style="{StaticResource FormControl}" Text="{Binding Name,ValidatesOnDataErrors=True,NotifyOnValidationError=True,UpdateSourceTrigger=PropertyChanged}" />
                </Border>
            </StackPanel>
            <StackPanel Grid.Column="1" Style="{StaticResource Col}">
                <Label Content="Phone Number" Style="{StaticResource Formlabel}" />
                <Border Style="{StaticResource FormInputBorder}">
                    <TextBox x:Name="Phone" Style="{StaticResource FormControl}" Text="{Binding Phone,UpdateSourceTrigger=PropertyChanged}" />
                </Border>
            </StackPanel>
        </Grid>
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
            <Button Style="{StaticResource PrimaryButton}" Command="{Binding Create}">Create</Button>
            <Button>Reset</Button>
        </StackPanel>
    </DockPanel>
</StackPanel>

然后我创建了以下viewmodel

public class vendorviewmodel : viewmodel
{
    protected readonly IUnitOfWork UnitOfWork;
    private string _Name { get; set; }
    private string _Phone { get; set; }

    public vendorviewmodel()
        : this(new UnitOfWork())
    {
    }

    public vendorviewmodel(IUnitOfWork unitOfWork)
    {
        UnitOfWork = unitOfWork;
    }

    [required(ErrorMessage = "The name is required")]
    [MinLength(5,ErrorMessage = "Name must be more than or equal to 5 letters")] 
    [MaxLength(50,ErrorMessage = "Name must be less than or equal to 50 letters")] 
    public string Name
    {
        get { return _Name; }
        set
        {
            _Name = value;
            NotifyPropertyChanged();
        }
    }

    public string Phone
    {
        get { return _Phone; }
        set
        {
            _Phone = value;
            NotifyPropertyChanged();
        }
    }

    /// <summary>
    /// Gets the collection of customer loaded from the data store.
    /// </summary>
    public ICollection<vendor> vendors { get; private set; }

    protected void Addvendor()
    {
        var vendor = new vendor(Name,Phone);
        UnitOfWork.vendors.Add(vendor);
    }

    public ICommand Create
    {
        get
        {
            return new ActionCommand(p => Addvendor(),p => IsValidRequest());
        }
    }

    public bool IsValidRequest()
    {
        // There got to be a better way to check if everything passed or Now...
        return IsValid("Name") && IsValid("Phone");
    }
}

这是我的viewmodel基类的样子

public abstract class viewmodel : ObservableObject,IDataErrorInfo
{
    /// <summary>
    /// Gets the validation error for a property whose name matches the specified <see cref="columnName"/>.
    /// </summary>
    /// <param name="columnName">The name of the property to validate.</param>
    /// <returns>Returns a validation error if there is one,otherwise returns null.</returns>
    public string this[string columnName]
    {
        get { return OnValidate(columnName); }
    }

    /// <summary>
    /// Validates a property whose name matches the specified <see cref="propertyName"/>.
    /// </summary>
    /// <param name="propertyName">The name of the property to validate.</param>
    /// <returns>Returns a validation error,if any,otherwise returns null.</returns>
    protected virtual string OnValidate(string propertyName)
    {
        var context = new ValidationContext(this)
        {
            MemberName = propertyName
        };

        var results = new Collection<ValidationResult>();
        bool isValid = Validator.TryValidateObject(this,context,results,true);

        if (!isValid)
        {
            ValidationResult result = results.SingleOrDefault(p =>                                                                  p.MemberNames.Any(memberName => memberName == propertyName));
            if (result != null)
                return result.ErrorMessage;
        }
        return null;
    }

    protected virtual bool IsValid(string propertyName)
    {
        return OnValidate(propertyName) == null;
    }

    /// <summary>
    /// Not supported.
    /// </summary>
    [Obsolete]
    public string Error
    {
        get
        {
            throw new NotSupportedException();
        }
    }
}

这是我的ObservableObject类

public class ObservableObject : INotifyPropertyChanged
{
    /// <summary>
    /// Raised when the value of a property has changed.
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Raises <see cref="PropertyChanged"/> for the property whose name matches <see cref="propertyName"/>.
    /// </summary>
    /// <param name="propertyName">Optional. The name of the property whose value has changed.</param>
    protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChangedEventHandler handler = PropertyChanged;

        if (handler != null)
        {
            handler(this,new PropertyChangedEventArgs(propertyName));
        }
    }
}

我的目标是在不正确的字段周围显示一个红色边框,然后在它下面显示错误消息,告诉使用出了什么问题.

如何正确显示错误?另外,如何在首次加载视图时不显示任何错误

基于此blog,我需要编辑Validation.ErrorTemplate

所以我尝试将以下代码添加到App.xaml文件

<!-- Style the error validation by showing the text message under the field -->
    <Style targettype="TextBox">
        <Setter Property="Validation.ErrorTemplate">
            <Setter.Value>
                <ControlTemplate>
                    <StackPanel>
                        <Border BorderThickness="1" BorderBrush="DarkRed">
                            <StackPanel>
                                <AdornedElementPlaceholder x:Name="errorControl" />
                            </StackPanel>
                        </Border>
                        <TextBlock Text="{Binding AdornedElement.ToolTip,ElementName=errorControl}" Foreground="Red" />
                    </StackPanel>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="BorderBrush" Value="Red" />
                <Setter Property="BorderThickness" Value="1" />
                <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self},Path=(Validation.Errors)[0].ErrorContent}" />
            </Trigger>
        </Style.Triggers>
    </Style>

但是这没有显示错误消息,也是在第一次加载视图时我得到一个错误.最后,即使表单生效,操作按钮也会保持禁用状态.

更新
将Property =“Validation.ErrorTemplate”移动到FormControl组后,它工作了.但是,错误消息似乎是通过按钮而不是按下按钮.此外,文本似乎没有垂直包装,允许边框覆盖其他控件,如下面的屏幕显示所示.

enter image description here


enter image description here


enter image description here

解决方法

我会尽力回答你的所有问题:

如何正确显示错误

不应用ErrorTemplate,因为TextBox上的FormControl样式优先于包含Validation.ErrorTemplate的样式.将Validation.ErrorTemplate代码移动到FormControl样式将解决此问题.

另外,如何在首次加载视图时不显示任何错误

如果不立即应用,必要验证的用途是什么?只有在开始键入字段时才会执行MinLength和MaxLength验证.

但是,错误消息似乎是通过按钮而不是按下按钮.

正如Will指出的那样,这是因为错误消息显示在AdornerLayer上,它不会干扰控件所在的层.您有以下选择:

>使用AdornerLayer但在控件之间留出一些空间
>使用工具提示显示错误消息
>在TextBox的模板中使用额外的TextBlock,以显示错误消息.

这些选项描述为here

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐