为什么 CellEditEnding 中的 MessageBox 会阻止执行 DataGrid 中的按钮功能?
Why does MessageBox in CellEditEnding prevent execution of button function in DataGrid?
对不起,如果它是微不足道的,但过去几天一直困扰着我。
我有一个 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。
但是如果用户仍在编辑单元格并按下 Save/Enter 按钮并且 输入无效 则有两种情况:
首先触发 cellEditEnding 事件(谁能告诉我为什么?)并且上面的函数运行导致 MessageBox 显示。但是当我关闭 MessageBox 时 Console.WriteLine("MessageBox Ended now!");
运行并且原始 Save/Button 函数没有被执行。
如果我评论MessageBox.Show()
行。 cellEditEnding 事件被触发,上面的函数照常运行,然后是 Save/Enter 按钮函数的代码。
为什么 MessageBox 会阻止执行 Save/Enter 按钮功能?
P.S:如果输入无效,我不希望执行回车按钮。但是不明白为什么使用 MessageBox 有助于实现这一目标?
我的评论应该解释发生了什么。
如果我可以提出建议,我不会使用 MessageBox 来显示不正确的输入。 MessageBoxes 可能会很痛苦。
相反,我建议看一下 DataGrid 控件验证。
我刚下班,所以我没有时间给你看一个例子,但我可以稍后回家。
对不起,我昨晚回到家时完全忘记了这件事。
好的,这是我今天早上提出的一个非常简单的示例,您可以执行一些数据网格行验证。它相当简单,但应该给你一些想法。我正在模型中进行实际验证。如果其中一个属性不在 0 - 10 I return 范围内,则会在工具提示中显示一个错误。
主窗口
在 MainWindow 中,我创建了数据网格并将其绑定到 SalesFigures 类型的可观察集合。我还为数据网格创建了一个样式,用于向用户显示行错误。
<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>
销售数据
下面是销售数字对象。我实现了 IDataErrorInfo,它公开了一个索引器和一个用于向 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;
}
}
}
}
销售验证规则
该规则用于确定模型 (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 ) );
}
}
}
对不起,如果它是微不足道的,但过去几天一直困扰着我。 我有一个 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。 但是如果用户仍在编辑单元格并按下 Save/Enter 按钮并且 输入无效 则有两种情况:
首先触发 cellEditEnding 事件(谁能告诉我为什么?)并且上面的函数运行导致 MessageBox 显示。但是当我关闭 MessageBox 时
Console.WriteLine("MessageBox Ended now!");
运行并且原始 Save/Button 函数没有被执行。如果我评论
MessageBox.Show()
行。 cellEditEnding 事件被触发,上面的函数照常运行,然后是 Save/Enter 按钮函数的代码。
为什么 MessageBox 会阻止执行 Save/Enter 按钮功能?
P.S:如果输入无效,我不希望执行回车按钮。但是不明白为什么使用 MessageBox 有助于实现这一目标?
我的评论应该解释发生了什么。 如果我可以提出建议,我不会使用 MessageBox 来显示不正确的输入。 MessageBoxes 可能会很痛苦。
相反,我建议看一下 DataGrid 控件验证。 我刚下班,所以我没有时间给你看一个例子,但我可以稍后回家。
对不起,我昨晚回到家时完全忘记了这件事。 好的,这是我今天早上提出的一个非常简单的示例,您可以执行一些数据网格行验证。它相当简单,但应该给你一些想法。我正在模型中进行实际验证。如果其中一个属性不在 0 - 10 I return 范围内,则会在工具提示中显示一个错误。
主窗口 在 MainWindow 中,我创建了数据网格并将其绑定到 SalesFigures 类型的可观察集合。我还为数据网格创建了一个样式,用于向用户显示行错误。
<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>
销售数据 下面是销售数字对象。我实现了 IDataErrorInfo,它公开了一个索引器和一个用于向 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;
}
}
}
}
销售验证规则 该规则用于确定模型 (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 ) );
}
}
}