WPF MVVM DataGrid是行已经有验证错误 [英] WPF MVVM DataGrid is row has has validation error
问题描述
这里的anwser https://social.msdn.microsoft.com/Forums/vstudio/en-US/18ea596e-ae96-481c-a928-a51c23fbf912/datagrid-blankcell-validationrules-and-mvvm-problem?论坛= wpf#26dadcb6-9d30-4f70-b556-89fdda8d960d帮助我将验证规则应用于数据网格中的
行
i有这个类让我改变数据网格中的项目
公共类DataGridSelectedItemsBlendBehavior:Behavior< DataGrid>
{
public static readonly DependencyProperty HasValidationErrorProperty =
DependencyProperty.Register(" HasValidationError",typeof(bool),
typeof(DataGridSelectedItemsBlendBehavior),
new FrameworkPropertyMetadata(null )
{
BindsTwoWayByDefault = true
});
public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register(" SelectedItems",typeof(IList),
typeof(DataGridSelectedItemsBlendBehavior),
new FrameworkPropertyMetadata(null)
{
BindsTwoWayByDefault = true
});
public static readonly DependencyProperty ChangedItemProperty =
DependencyProperty.Register(" ChangedItems",typeof(IList),
typeof(DataGridSelectedItemsBlendBehavior),
new FrameworkPropertyMetadata(null)
{
BindsTwoWayByDefault = true
});
public bool HasValidationError
{
get
{
return(bool)GetValue(HasValidationErrorProperty);
}
设置
{
SetValue(HasValidationErrorProperty,value);
}
}
public IList SelectedItems
{
get
{
return(IList)GetValue(SelectedItemProperty);
}
设置
{
SetValue(SelectedItemProperty,value);
}
}
public IList ChangedItems
{
get
{
return(IList)GetValue(ChangedItemProperty);
}
设置
{
SetValue(ChangedItemProperty,value);
}
}
protected override void OnAttached()
{
base.OnAttached();
this.AssociatedObject.SelectionChanged + = OnSelectionChanged;
this.AssociatedObject.RowEditEnding + = OnRowEditEnding;
this.AssociatedObject.Loaded + = AssociatedObject_Loaded;
}
void AssociatedObject_Loaded(对象发送者,RoutedEventArgs e)
{
if(this.SelectedItems!= null)
{
var selectedItems = this.SelectedItems;
foreach(var obj in selectedItems)
{
var rowContainer = this.AssociatedObject.ItemContainerGenerator.ContainerFromItem(obj)as DataGridRow;
if(rowContainer!= null)
{
rowContainer.IsSelected = true;
}
}
}
}
protected override void OnDetaching()
{
base.OnDetaching();
if(this.AssociatedObject!= null)
{
this.AssociatedObject.SelectionChanged - = OnSelectionChanged;
this.AssociatedObject.RowEditEnding - = OnRowEditEnding;
this.AssociatedObject.Loaded - = AssociatedObject_Loaded;
}
}
///< summary>
///基于用户与数据网格的交互,使用shift或ctrl按钮向所选项目集合添加/删除行
///< / summary>
private void OnSelectionChanged(object sender,SelectionChangedEventArgs e)
{
if(e.AddedItems!= null&& e.AddedItems.Count> 0&& this.SelectedItems != null)
{
foreach(e.AddedItems中的对象obj)
{
if(obj.ToString()==" {NewItemPlaceholder}")
{
继续;
}
this.SelectedItems.Add(obj);
}
}
if(e.RemovedItems!= null&& e.RemovedItems.Count> 0&& this.SelectedItems!= null)
{
foreach(e.RemovedItems中的对象obj)
{
this.SelectedItems.Remove(obj);
}
}
}
public static bool IsValid(DependencyObject obj)
{
return obj == null
? false
:!Validation.GetHasError(obj)&& LogicalTreeHelper.GetChildren(OBJ).OfType<&的DependencyObject GT;()所有(的IsValid)。
}
///< summary>
///将datagrid中的提交项添加到changeditems集合
///< / summary>
private void OnRowEditEnding(object sender,DataGridRowEditEndingEventArgs e)
{
if(e.EditAction == DataGridEditAction.Commit)
{
if(!IsValid(e。)行作为DependencyObject))
{
HasValidationError = true;
返回;
}
var item = ChangedItems.Cast< object>()。SingleOrDefault(i => i!= null);
if(item == null)
{
this.ChangedItems.Add(e.Row.Item);
}
else
{
item = e.Row.Item;
}
HasValidationError = false;
}
}
}
i想要停止将行添加到已更改的项目中,如果它有验证错误,但"e.row.item" for"DataGridRowEditEndingEventArgs"只有当我第一次开始编辑时才获取数据,例如,如果我添加了新行,则e.row.item
列"名称"即使我添加数据直到我点击进入并再次开始编辑是否有办法绕过它会是空的?或者更好的方法来了解某行是否有验证错误?
嗨艾哈迈德,
>> 想要停止将行添加到已更改的项目中,如果它有验证错误但是"e.row.item"
代表"DataGridRowEditEndingEventArgs"只有当我第一次开始编辑时才获取数据,例如,如果我添加了一行新的e.row.item列"名称"列。即使我添加了数据,直到我点击进入并再次开始编辑是
还有办法绕过它吗?或者更好的方法来了解某行是否有验证错误?
根据您的代码和描述,我不确定您想做什么。对于第一个线程,您希望对datagrid进行验证,但在属性更改时使用Validationrule
,因此我建议您使用 IDataErrorInfo来验证空。
当您使用IDataErrorInfo进行datagridrow时,您也可以使用validationRule,这不是问题。
< Window.Resources>
< Style x:Key =" TextBlockStyle" TargetType =" {x:Type TextBlock}">
< Style.Triggers>
< Trigger Property =" Validation.HasError"值= QUOT;真">
< Setter Property =" ToolTip" Value =" {Binding RelativeSource = {RelativeSource Self},Path =(Validation.Errors)[0] .ErrorContent}" />
< / Trigger>
< /Style.Triggers>
< / Style>
< Style x:Key =" errorStyle" TargetType =" {x:Type TextBox}">
< Setter Property =" Padding"值= QUOT; -2 QUOT; />
< Style.Triggers>
< Trigger Property =" Validation.HasError"值= QUOT;真">
< Setter Property =" Background"值= QUOT;红色" />
< Setter Property =" ToolTip" Value =" {Binding RelativeSource = {RelativeSource Self},Path =(Validation.Errors)[0] .ErrorContent}" />
< / Trigger>
< /Style.Triggers>
< / Style>
< /Window.Resources>
< Grid>
< DataGrid AutoGenerateColumns =" False" ItemsSource =" {Binding tests}">
< DataGrid.Columns>
< DataGridTextColumn
Width =" 100"
EditingElementStyle =" {StaticResource errorStyle}"
ElementStyle =" {StaticResource TextBlockStyle}"
Header =" FristName">
< DataGridTextColumn.Binding>
< Binding
NotifyOnValidationError =" True"
Path =" FirstName"
UpdateSourceTrigger =" PropertyChanged"
ValidatesOnDataErrors =" True">
< Binding.ValidationRules>
< local:NameValidationRule />
< /Binding.ValidationRules>
< / Binding>
< /DataGridTextColumn.Binding>
< / DataGridTextColumn>
< DataGridTextColumn
Width =" 100"
Binding =" {Binding LastName,UpdateSourceTrigger = PropertyChanged,NotifyOnValidationError = True,ValidatesOnDataErrors = True}"
ElementStyle =" {StaticResource TextBlockStyle}"
Header =" LastName" />
< DataGridTextColumn
Width =" 100"
EditingElementStyle =" {StaticResource errorStyle}"
Header =" Age">
< DataGridTextColumn.Binding>
< Binding
NotifyOnValidationError =" True"
Path =" Age"
UpdateSourceTrigger =" PropertyChanged"
ValidatesOnDataErrors =" True">
< Binding.ValidationRules>
< local:ValueValidationRule Max =" 100"敏= QUOT; 0" />
< /Binding.ValidationRules>
< / Binding>
< /DataGridTextColumn.Binding>
< / DataGridTextColumn>
< DataGridTextColumn
Width =" 100"
Binding =" {Binding Sex}"
标题="性别" />
< /DataGrid.Columns>
< / DataGrid>
< / Grid>
公共部分类Window13:Window
{
public ObservableCollection< testvalidation>测试{得到;组; }
public Window13()
{
InitializeComponent();
tests = new ObservableCollection< testvalidation>()
{
new testvalidation(){FirstName =" a",LastName =" aa",Age = 12,Sex =" woman" ;},
new testvalidation(){FirstName =" a",LastName =" aa",Age = 12,Sex =" woman"},
new testvalidation(){FirstName =" ; a",LastName =" aa",Age = 12,Sex =" woman"},
new testvalidation(){FirstName =" a",LastName =" aa",Age = 12,性别="女人"},
新的testvalidation(){FirstName =" a",LastName =" aa",Age = 12,Sex =" woman"},
new testvalidation( ){FirstName =" a",LastName =" aa",Age = 12,Sex =" woman"},
};
this.DataContext = this;
}
}
公共类testvalidation:ViewModelBase,IDataErrorInfo
{
公共字符串错误
{
get
{
return String.Empty;
}
}
public string this [string columnName]
{
get
{
string errorMessage = null;
switch(columnName)
{
case" FirstName":
if(String.IsNullOrWhiteSpace(FirstName))
{
errorMessage =" FirstName是必需的。";
}
休息;
case" LastName":
if(String.IsNullOrWhiteSpace(LastName))
{
errorMessage =" LasttName is required。";
}
休息;
}
返回errorMessage;
}
}
private string _FirstName;
public string FirstName
{
get {return _FirstName; }
设置
{
_FirstName = value;
RaisePropertyChanged(" FirstName");
}
}
public string LastName {get;组; }
public int Age {get;组; }
public string Sex {get;组; }
}
class ValueValidationRule:ValidationRule
{
private int _min;
private int _max;
public ValueValidationRule()
{
}
public int Min
{
get {return _min ; }
set {_min = value; }
}
public int Max
{
get {return _max; }
set {_max = value; }
}
公共覆盖ValidationResult Validate(对象值,CultureInfo cultureInfo)
{
int age = 0;
try
{
if(((string)value).Length> 0)
age = Int32.Parse((String)value);
}
catch(例外e)
{
返回新的ValidationResult(false,"非法字符或"+ e.Message);
}
if((age< Min)||(age> Max))
{
返回新的ValidationResult(false,
" ;请输入以下范围内的年龄:"+ Min +" - " + Max +"。");
}
其他
{
返回ValidationResult.ValidResult;
}
}
}
class NameValidationRule:ValidationRule
{
public NameValidationRule()
{
}
公共覆盖ValidationResult Validate(对象值,CultureInfo cultureInfo)
{
string name ="" ;;
try
{
if(((string)value).Length> 0)
name =((String)value);
}
catch(例外e)
{
返回新的ValidationResult(false,"非法字符或"+ e.Message);
}
if(name =="")
{
返回新的ValidationResult(false,
" Please enter Name") ;
}
其他
{
返回ValidationResult.ValidResult;
}
}
}如果你想知道这行是否有验证错误,你可以拿一个查看以下主题:
https ://stackoverflow.com/questions/7121892/wpf-detect-row-validation-errors-in-c-sharp-code
最好的问候,
Cherry
the anwser here https://social.msdn.microsoft.com/Forums/vstudio/en-US/18ea596e-ae96-481c-a928-a51c23fbf912/datagrid-blankcell-validationrules-and-mvvm-problem?forum=wpf#26dadcb6-9d30-4f70-b556-89fdda8d960d helped me to apply validation rules to a
row in datagrid
i had this class to get me changed items in the datagrid
public class DataGridSelectedItemsBlendBehavior : Behavior<DataGrid> { public static readonly DependencyProperty HasValidationErrorProperty = DependencyProperty.Register("HasValidationError", typeof(bool), typeof(DataGridSelectedItemsBlendBehavior), new FrameworkPropertyMetadata(null) { BindsTwoWayByDefault = true }); public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItems", typeof(IList), typeof(DataGridSelectedItemsBlendBehavior), new FrameworkPropertyMetadata(null) { BindsTwoWayByDefault = true }); public static readonly DependencyProperty ChangedItemProperty = DependencyProperty.Register("ChangedItems", typeof(IList), typeof(DataGridSelectedItemsBlendBehavior), new FrameworkPropertyMetadata(null) { BindsTwoWayByDefault = true }); public bool HasValidationError { get { return (bool)GetValue(HasValidationErrorProperty); } set { SetValue(HasValidationErrorProperty, value); } } public IList SelectedItems { get { return (IList)GetValue(SelectedItemProperty); } set { SetValue(SelectedItemProperty, value); } } public IList ChangedItems { get { return (IList)GetValue(ChangedItemProperty); } set { SetValue(ChangedItemProperty, value); } } protected override void OnAttached() { base.OnAttached(); this.AssociatedObject.SelectionChanged += OnSelectionChanged; this.AssociatedObject.RowEditEnding += OnRowEditEnding; this.AssociatedObject.Loaded += AssociatedObject_Loaded; } void AssociatedObject_Loaded(object sender, RoutedEventArgs e) { if (this.SelectedItems != null) { var selectedItems = this.SelectedItems; foreach (var obj in selectedItems) { var rowContainer = this.AssociatedObject.ItemContainerGenerator.ContainerFromItem(obj) as DataGridRow; if (rowContainer != null) { rowContainer.IsSelected = true; } } } } protected override void OnDetaching() { base.OnDetaching(); if (this.AssociatedObject != null) { this.AssociatedObject.SelectionChanged -= OnSelectionChanged; this.AssociatedObject.RowEditEnding -= OnRowEditEnding; this.AssociatedObject.Loaded -= AssociatedObject_Loaded; } } /// <summary> /// Add/remove row to selected items collection based on user interaction with the datagrid with shift or ctrl buttons /// </summary> private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) { if (e.AddedItems != null && e.AddedItems.Count > 0 && this.SelectedItems != null) { foreach (object obj in e.AddedItems) { if (obj.ToString() == "{NewItemPlaceholder}") { continue; } this.SelectedItems.Add(obj); } } if (e.RemovedItems != null && e.RemovedItems.Count > 0 && this.SelectedItems != null) { foreach (object obj in e.RemovedItems) { this.SelectedItems.Remove(obj); } } } public static bool IsValid(DependencyObject obj) { return obj == null ? false : !Validation.GetHasError(obj) && LogicalTreeHelper.GetChildren(obj).OfType<DependencyObject>().All(IsValid); } /// <summary> /// add the commited items in the datagrid to changeditems collection /// </summary> private void OnRowEditEnding(object sender, DataGridRowEditEndingEventArgs e) { if (e.EditAction == DataGridEditAction.Commit) { if (!IsValid(e.Row as DependencyObject)) { HasValidationError = true; return; } var item = ChangedItems.Cast<object>().SingleOrDefault(i => i != null); if (item == null) { this.ChangedItems.Add(e.Row.Item); } else { item = e.Row.Item; } HasValidationError = false; } } }
i want to stop adding the row to the changed items if it has a validation error but the "e.row.item" for "DataGridRowEditEndingEventArgs" only gets the data when i first start editing for example if i added a new row the e.row.item
column "Name" will be empty even if i added data to it until i hit enter and start editing again is there is a way to get a around it? or a better way to know if a row has a validation error ?
Hi Ahmed,
>> want to stop adding the row to the changed items if it has a validation error but the "e.row.item" for "DataGridRowEditEndingEventArgs" only gets the data when i first start editing for example if i added a new row the e.row.item column "Name" will be empty even if i added data to it until i hit enter and start editing again is there is a way to get a around it? or a better way to know if a row has a validation error ?
According to your code and description, I am not sure what you want to do. For the first thread, you want to have validation for datagrid, but the Validationrule is used when the property changed, so I suggest you to use IDataErrorInfo to validate the empty.
You can also use validationRule when you use IDataErrorInfo for datagridrow, it is not a problem.
<Window.Resources> <Style x:Key="TextBlockStyle" TargetType="{x:Type TextBlock}"> <Style.Triggers> <Trigger Property="Validation.HasError" Value="true"> <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" /> </Trigger> </Style.Triggers> </Style> <Style x:Key="errorStyle" TargetType="{x:Type TextBox}"> <Setter Property="Padding" Value="-2" /> <Style.Triggers> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="Background" Value="Red" /> <Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" /> </Trigger> </Style.Triggers> </Style> </Window.Resources> <Grid> <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding tests}"> <DataGrid.Columns> <DataGridTextColumn Width="100" EditingElementStyle="{StaticResource errorStyle}" ElementStyle="{StaticResource TextBlockStyle}" Header="FristName"> <DataGridTextColumn.Binding> <Binding NotifyOnValidationError="True" Path="FirstName" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True"> <Binding.ValidationRules> <local:NameValidationRule /> </Binding.ValidationRules> </Binding> </DataGridTextColumn.Binding> </DataGridTextColumn> <DataGridTextColumn Width="100" Binding="{Binding LastName, UpdateSourceTrigger=PropertyChanged, NotifyOnValidationError=True, ValidatesOnDataErrors=True}" ElementStyle="{StaticResource TextBlockStyle}" Header="LastName" /> <DataGridTextColumn Width="100" EditingElementStyle="{StaticResource errorStyle}" Header="Age"> <DataGridTextColumn.Binding> <Binding NotifyOnValidationError="True" Path="Age" UpdateSourceTrigger="PropertyChanged" ValidatesOnDataErrors="True"> <Binding.ValidationRules> <local:ValueValidationRule Max="100" Min="0" /> </Binding.ValidationRules> </Binding> </DataGridTextColumn.Binding> </DataGridTextColumn> <DataGridTextColumn Width="100" Binding="{Binding Sex}" Header="Sex" /> </DataGrid.Columns> </DataGrid> </Grid>
public partial class Window13 : Window { public ObservableCollection<testvalidation> tests { get; set; } public Window13() { InitializeComponent(); tests = new ObservableCollection<testvalidation>() { new testvalidation(){FirstName="a",LastName="aa",Age=12,Sex="woman"}, new testvalidation(){FirstName="a",LastName="aa",Age=12,Sex="woman"}, new testvalidation(){FirstName="a",LastName="aa",Age=12,Sex="woman"}, new testvalidation(){FirstName="a",LastName="aa",Age=12,Sex="woman"}, new testvalidation(){FirstName="a",LastName="aa",Age=12,Sex="woman"}, new testvalidation(){FirstName="a",LastName="aa",Age=12,Sex="woman"}, }; this.DataContext = this; } } public class testvalidation : ViewModelBase, IDataErrorInfo { public string Error { get { return String.Empty; } } public string this[string columnName] { get { string errorMessage = null; switch (columnName) { case "FirstName": if (String.IsNullOrWhiteSpace(FirstName)) { errorMessage = "FirstName is required."; } break; case "LastName": if (String.IsNullOrWhiteSpace(LastName)) { errorMessage = "LasttName is required."; } break; } return errorMessage; } } private string _FirstName; public string FirstName { get { return _FirstName; } set { _FirstName = value; RaisePropertyChanged("FirstName"); } } public string LastName { get; set; } public int Age { get; set; } public string Sex { get; set; } }
class ValueValidationRule : ValidationRule { private int _min; private int _max; public ValueValidationRule() { } public int Min { get { return _min; } set { _min = value; } } public int Max { get { return _max; } set { _max = value; } } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { int age = 0; try { if (((string)value).Length > 0) age = Int32.Parse((String)value); } catch (Exception e) { return new ValidationResult(false, "Illegal characters or " + e.Message); } if ((age < Min) || (age > Max)) { return new ValidationResult(false, "Please enter an age in the range: " + Min + " - " + Max + "."); } else { return ValidationResult.ValidResult; } } } class NameValidationRule : ValidationRule { public NameValidationRule() { } public override ValidationResult Validate(object value, CultureInfo cultureInfo) { string name = ""; try { if (((string)value).Length > 0) name = ((String)value); } catch (Exception e) { return new ValidationResult(false, "Illegal characters or " + e.Message); } if (name=="") { return new ValidationResult(false, "Please enter Name "); } else { return ValidationResult.ValidResult; } } }If you want to know if the row has a validation error, you can take a look the following thread:
https://stackoverflow.com/questions/7121892/wpf-detect-row-validation-errors-in-c-sharp-code
Best Regards,
Cherry
这篇关于WPF MVVM DataGrid是行已经有验证错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!