为什么CellEditEnding中的MessageBox会阻止DataGrid中按钮函数的执行

本文关键字:按钮 函数 执行 DataGrid 中的 CellEditEnding MessageBox 为什么 | 更新日期: 2023-09-27 18:15:35

很抱歉,如果这是微不足道的,但它已经困扰了我几天了。我有一个DataGrid,其中用户可以编辑单元格的条目。

为了在传递给网格的ItemSource(一个列表)之前验证数据,我有一个绑定到CellEditEnding事件的函数。
todayspecialextra.CellEditEnding += ExtraEntry_CellEditEnding;
private void ExtraEntry_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
    {
        if (e.EditAction == DataGridEditAction.Commit)
        {
                   ....
                   // element.Text has the new, user-entered value
                    var element = e.EditingElement as TextBox;
                    int x;
                    if (!(int.TryParse(element.Text, out x) && x >= 0 && x <= 10))
                    {
                        element.Text = "0";
                        MessageBox.Show("Quantity allowed >0 and <10");
                        Console.WriteLine("MessageBox Ended now!");
                    }
         }
    }

private void button_enter_Click(object sender, RoutedEventArgs e)
{
  ...
}

通常情况下,如果用户正在编辑单元格并输入无效值。他得到一个MessageBox对话框,其值本身变为0。但是,如果用户仍在编辑单元格并按下保存/输入按钮和,则输入无效有两种情况:

  1. 首先触发cellleditending事件(有人知道为什么吗?),上面的函数运行导致MessageBox显示。但是当我关闭MessageBox Console.WriteLine("MessageBox Ended now!");运行时,原始的保存/按钮功能不会被执行。

  2. 如果我注释MessageBox.Show()行。触发cellleditending事件,上述函数像往常一样运行,后面跟着Save/Enter按钮函数的代码。

为什么MessageBox阻止保存/进入按钮功能的执行?

p。S:我不想在输入无效的情况下执行回车键。但不能理解为什么使用MessageBox有助于实现这一点?

为什么CellEditEnding中的MessageBox会阻止DataGrid中按钮函数的执行

我的评论应该解释发生了什么。如果我可以提出建议,我不会使用MessageBox来显示错误的输入。消息框可能很麻烦。

相反,我建议看一下DataGrid控件验证。我刚下班,所以我没有时间给你展示一个例子,但我可以等我回家。

对不起,我昨晚回家的时候把这件事完全忘了。好的,这是一个非常简单的例子,我今天早上突然想到一些数据网格行验证,你可以做。这是相当简单的,但应该给你一些想法。我在模型中做实际验证。如果其中一个属性不在0 - 10范围内,则返回一个错误,并在工具提示中显示。

主窗口在MainWindow中,我创建了数据网格,并将其绑定到SalesFigures类型的可观察集合。我还为datagdrow创建了一个样式,用于向用户显示行错误。

<Window x:Class="DataGridValidation.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:DataGridValidation"
    xmlns:vm="clr-namespace:DataGridValidation.ViewModels"
    xmlns:rules="clr-namespace:DataGridValidation.Validation"
    mc:Ignorable="d"
    Title="MainWindow" 
    Height="350" Width="525">
<Window.DataContext>
    <vm:MainViewModel/>
</Window.DataContext>
<Grid>
    <DataGrid ItemsSource="{Binding Sales}"
              AutoGenerateColumns="False">
        <!-- Row validation rule -->
        <DataGrid.RowValidationRules>
            <rules:SalesValidationRule ValidationStep="UpdatedValue"/>
        </DataGrid.RowValidationRules>
        <DataGrid.Resources>
            <!-- DataGridRow template for displaying the error -->
            <Style TargetType="{x:Type DataGridRow}">
                <Style.Triggers>
                    <Trigger Property="Validation.HasError" Value="true">
                        <Setter Property="BorderThickness" Value="1"/>
                        <Setter Property="BorderBrush" Value="Red"/>
                        <Setter Property="ToolTip"
                            Value="{Binding RelativeSource={RelativeSource Self},
                            Path=(Validation.Errors)[0].ErrorContent}"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Pie" 
                                Binding="{Binding Pie, ValidatesOnExceptions=True}"/>
            <DataGridTextColumn Header="Cake" Binding="{Binding Cake, ValidatesOnExceptions=True}"/>
            <DataGridTextColumn Header="Candy" Binding="{Binding Candy, ValidatesOnExceptions=True}"/>
            <DataGridTextColumn Header="Chocolate" Binding="{Binding, ValidatesOnExceptions=True Chocolate}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

SalesFigures 下面是销售数字对象。我实现了IDataErrorInfo,它公开了一个索引器和一个Error属性,用于向UI显示自定义错误信息。如果您计划以编程方式更新模型属性,您还应该实现INotifyPropertyChanged接口。

using System;
using System.ComponentModel;
using System.Linq;
namespace DataGridValidation.Entities
{
public class SalesFigures : IDataErrorInfo
{
    public decimal Pie { get; set; }
    public decimal Cake { get; set; }
    public decimal Candy { get; set; }
    public decimal Chocolate { get; set; }
    public string this[ string columnName ]
    {
        get
        {
            string result = null;
            switch( columnName )
            {
                case nameof( Pie ):
                    result = ValidateValue( nameof( Pie ), Pie );
                    break;
                case nameof( Cake ):
                    result = ValidateValue( nameof( Cake ), Cake );
                    break;
                case nameof( Candy ):
                    result = ValidateValue( nameof( Candy ), Candy );
                    break;
                case nameof( Chocolate ):
                    result = ValidateValue( nameof( Chocolate ), Chocolate );
                    break;
                default:
                    break;
            }
            return result;
        }
    }

    public string ValidateValue( string name, decimal value )
    {
        if( value < 0 )
        {
            return $"{name} must be greater than or equal to zero";
        }
        if( value > 10 )
        {
            return $"{name} must be equal to or less than 10";
        }
        return string.Empty;
    }
    public string Error
    {
        get
        {
            var errors = string.Empty;
            // Get all properties of object.
            var properties = TypeDescriptor.GetProperties( this );
            // Iterate through every property and look
            // for errors.
            foreach( var property in properties.Cast<PropertyDescriptor>() )
            {
                var propertyError = this[ property.Name ];
                if( !string.IsNullOrWhiteSpace( propertyError ) )
                {
                    errors += $"{propertyError}{Environment.NewLine}";
                }
            }
            return errors;
        }
    }
}

}

SalesValidationRule 该规则用于确定模型(SalesFigures)是否遇到任何错误。

using System;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Data;
namespace DataGridValidation.Validation
{
public class SalesValidationRule : ValidationRule
{
    public override ValidationResult Validate( object value, CultureInfo cultureInfo )
    {
        var bindingGroup = ( BindingGroup )value;
        if( bindingGroup == null )
            return null;
        var errors = string.Empty;
        foreach( var item in bindingGroup.Items.OfType<IDataErrorInfo>() )
        {
            if( !string.IsNullOrWhiteSpace( item.Error ) )
            {
                errors += $"{item.Error}{Environment.NewLine}";
            }
        }
        if( !string.IsNullOrWhiteSpace( errors ) )
        {
            return new ValidationResult( false, errors );
        }
        return ValidationResult.ValidResult;
    }
}

}

MainViewModel 为了完整起见,这是MainWindow绑定到的MainViewModel。这里我只是用一些随机数据填充DataGrid。

using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using DataGridValidation.Annotations;
using DataGridValidation.Entities;
namespace DataGridValidation.ViewModels
{
public class MainViewModel : INotifyPropertyChanged
{
    public MainViewModel( )
    {
        var random = new Random( );
        for( int i = 0; i < 15; i++ )
        {
            Sales.Add(
                new SalesFigures
                {
                    Cake = random.Next( 0, 11 ),
                    Candy = random.Next( 0, 11 ),
                    Chocolate = random.Next( 0, 11 ),
                    Pie = random.Next( 0, 11 )
                } );
        }
    }
    public ObservableCollection<SalesFigures> Sales { get; } =
        new ObservableCollection<SalesFigures>( );

    public event PropertyChangedEventHandler PropertyChanged;
    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged( [CallerMemberName] string propertyName = null )
    {
        PropertyChanged?.Invoke( this, new PropertyChangedEventArgs( propertyName ) );
    }
}

}