簡體   English   中英

單擊保存按鈕上的IDataErrorInfo錯誤消息框

[英]IDataErrorInfo error messagebox on save button click

我正在構建一個wpf應用程序,並且在類中實現了IDataErrorInfo接口。 一切正常, textbox已正確綁定,帶有錯誤消息的工具提示正確顯示,並且屬性更改時邊框變為紅色。

但是,當我單擊“保存”按鈕(創建我的實體並將其保存到數據庫中)時,即使文本框中的值錯誤,也會將錯誤的值保存在數據庫中。

過去,我在屬性設置器中使用過ArgumentException ,然后單擊“保存”按鈕時,在try / catch內顯示了一個帶有錯誤消息的消息框,但未保存我的錯誤值。

有沒有類似的方法來實現消息框,例如try / catch一個,但使用IDataErrorInfo

我不是在尋找復雜的解決方案,因為我是一個初學者,這是我第一次嘗試使用IDataErrorInfo

由於有評論,我將答案更新為更詳細的答案。

首先, Newspeak是Ingsoc,而Ingsoc是Newspeak, XAML是MVVM,而MVVM是XAML。

要編寫與“ Hello,world”截然不同的內容,您必須特別學習MVVM和命令。 下面的代碼使用以下ICommand實現:

public sealed class RelayCommand : ICommand
{
    private readonly Action execute;
    private readonly Func<bool> canExecute;

    public RelayCommand(Action execute, Func<bool> canExecute)
    {
        this.execute = execute;
        this.canExecute = canExecute;
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public bool CanExecute(object parameter)
    {
        return canExecute();
    }

    public void Execute(object parameter)
    {
        execute();
    }
}

在現實世界的應用程序中,WPF驗證使用一些知名的驗證框架卧底,並且幾乎永遠不會在需要驗證的每個視圖模型中手動實現。

這是在IDataErrorInfo驗證的示例,該驗證在基類中使用數據批注實現

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

    protected virtual void OnPropertyChanged([CallerMemberName]string propertyName = null)
    {
        // updating property-bound controls
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        // updating command-bound controls like buttons
        CommandManager.InvalidateRequerySuggested();
    }

    private readonly ObservableCollection<ViewModelError> validationErrors = new ObservableCollection<ViewModelError>();

    private void RemoveValidationErrors(string propertyName)
    {
        var propertyValidationErrors = validationErrors
            .Where(_ => _.PropertyName == propertyName)
            .ToArray();

        foreach (var error in propertyValidationErrors)
        {
            validationErrors.Remove(error);
        }
    }

    private string ValidateProperty(string propertyName)
    {
        // we need localized property name
        var property = GetType().GetProperty(propertyName);
        var displayAttribute = property.GetCustomAttribute<DisplayAttribute>();
        var propertyDisplayName = displayAttribute != null ? displayAttribute.GetName() : propertyName;

        // since validation engine run all validation rules for property,
        // we need to remove validation errors from the previous validation attempt
        RemoveValidationErrors(propertyDisplayName);

        // preparing validation engine
        var validationContext = new ValidationContext(this, null, null) { MemberName = propertyName };
        var validationResults = new List<ValidationResult>();

        // running validation
        if (!Validator.TryValidateProperty(property.GetValue(this), validationContext, validationResults))
        {
            // validation is failed;
            // since there could be several validation rules per property, 
            // validation results can contain more than single error
            foreach (var result in validationResults)
            {
                validationErrors.Add(new ViewModelError(propertyDisplayName, result.ErrorMessage));
            }

            // to indicate validation error, it's enough to return first validation message
            return validationResults[0].ErrorMessage;
        }

        return null;
    }

    public IEnumerable<ViewModelError> ValidationErrors
    {
        get { return validationErrors; }
    }

    public string this[string columnName]
    {
        get { return ValidateProperty(columnName); }
    }

    public string Error
    {
        get { return null; }
    }
}

ViewModelError只是一個容器:

public sealed class ViewModelError
{
    public ViewModelError(string propertyName, string errorMessage)
    {
        PropertyName = propertyName;
        ErrorMessage = errorMessage;
    }

    public string PropertyName { get; private set; }
    public string ErrorMessage { get; private set; }
}

讓我們看一下表示一些人數據的模型,相應的視圖模型和視圖:

一個模型

public class Person
{
    public Guid Id { get; set; }
    public string Name { get; set; }
    public int Age { get; set; }
}

b)視圖模型

public class PersonViewModel : ViewModel
{
    private void HandleSave()
    {
        var person = new Person
        {
            Id = Guid.NewGuid(),
            Name = Name,
            Age = Age
        };

        // save person using database, web service, file...
    }

    private bool CanSave()
    {
        return !ValidationErrors.Any();
    }

    public PersonViewModel()
    {
        SaveCommand = new RelayCommand(HandleSave, CanSave);
    }

    [Display(Name = "Full name of person")]
    [Required(AllowEmptyStrings = false)]
    [MaxLength(50)]
    public string Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                OnPropertyChanged();
            }
        }
    }
    private string name;

    [Display(Name = "Age of person")]
    [Range(18, 65)]
    public int Age
    {
        get { return age; }
        set
        {
            if (age != value)
            {
                age = value;
                OnPropertyChanged();
            }
        }
    }
    private int age;

    public ICommand SaveCommand { get; private set; }
}

c)視圖(WPF窗口)

<Window x:Class="Wpf_IDataErrorInfoSample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Wpf_IDataErrorInfoSample"
        mc:Ignorable="d"
        Title="MainWindow" Height="300" Width="400">

    <Window.DataContext>
        <local:PersonViewModel />
    </Window.DataContext>

    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!-- Validation summary -->
        <ItemsControl ItemsSource="{Binding ValidationErrors}">
            <ItemsControl.ItemTemplate>
                <DataTemplate DataType="{x:Type local:ViewModelError}">
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding PropertyName}"/>
                        <TextBlock Text=" : "/>
                        <TextBlock Text="{Binding ErrorMessage}"/>
                    </StackPanel>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>

        <!-- Editable fields -->
        <StackPanel Grid.Row="1" Margin="4, 10, 4, 4">
            <!-- Name -->
            <TextBlock Text="Name:"/>
            <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>

            <!-- Age -->
            <TextBlock Text="Age:"/>
            <Slider Minimum="0" Maximum="120" TickPlacement="BottomRight" Value="{Binding Age, ValidatesOnDataErrors=True}"/>
        </StackPanel>

        <Button Grid.Row="2" Content="Save" Command="{Binding SaveCommand}"/>
    </Grid>
</Window>

如果運行此代碼,則初始圖片如下所示:

在此處輸入圖片說明

如您所見,如果存在驗證錯誤,該按鈕將被禁用,並且您將無法保存無效數據。 如果您要糾正錯誤,則該按鈕將變為啟用狀態,您可以單擊它來保存數據:

在此處輸入圖片說明

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM