C# WPF DataGrid文本框在出现多个验证错误时保留以前的值
我创建了一个包含两列的C# WPF DataGrid文本框在出现多个验证错误时保留以前的值,c#,wpf,xaml,datagrid,idataerrorinfo,C#,Wpf,Xaml,Datagrid,Idataerrorinfo,我创建了一个包含两列的DataGrid,这两列都使用TextBoxs来编辑ViewModel的属性。当两列都有验证错误,并且特性值从ViewModel更改时,在其中一个单元格中进入编辑模式将保留以前编辑的值 下面是一个简短的例子: 看法 我遇到了同样的问题,但是显式地将绑定模式设置为双向并不能解决这个问题 我是不是有什么地方做错了,我忽略了?或者,有人对此有解决办法吗?我找到了解决办法 如果我改为使用INotifyDataErrorInfo(仅在.NET 4.5及更高版本中可用),那么它将按预期
DataGrid
,这两列都使用TextBox
s来编辑ViewModel的属性。当两列都有验证错误,并且特性值从ViewModel更改时,在其中一个单元格中进入编辑模式将保留以前编辑的值
下面是一个简短的例子:
看法
我遇到了同样的问题,但是显式地将绑定模式设置为双向并不能解决这个问题
我是不是有什么地方做错了,我忽略了?或者,有人对此有解决办法吗?我找到了解决办法 如果我改为使用
INotifyDataErrorInfo
(仅在.NET 4.5及更高版本中可用),那么它将按预期工作
视图模型
公共类ItemPresenter:INotifyPropertyChanged,INotifyDataErrorInfo
{
公共事件属性更改事件处理程序属性更改;
公共事件事件处理程序错误更改;
公共字符串值1{get;set;}=“A”;
公共字符串值2{get;set;}=“B”;
public IEnumerable GetErrors(string propertyName)=>new[]{“ERROR”};
公共bool hasrerrors=>true;
公共无效重置()
{
Value1=“A”;
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(nameof(Value1));
ErrorsChanged?.Invoke(这是新数据ErrorSchangedEventArgs(nameof(Value1));
Value2=“B”;
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(nameof(Value2));
ErrorsChanged?.Invoke(这是新数据ErrorSchangedEventArgs(名称(值2));
}
}
看法
我找到了一个解决办法 如果我改为使用
INotifyDataErrorInfo
(仅在.NET 4.5及更高版本中可用),那么它将按预期工作
视图模型
公共类ItemPresenter:INotifyPropertyChanged,INotifyDataErrorInfo
{
公共事件属性更改事件处理程序属性更改;
公共事件事件处理程序错误更改;
公共字符串值1{get;set;}=“A”;
公共字符串值2{get;set;}=“B”;
public IEnumerable GetErrors(string propertyName)=>new[]{“ERROR”};
公共bool hasrerrors=>true;
公共无效重置()
{
Value1=“A”;
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(nameof(Value1));
ErrorsChanged?.Invoke(这是新数据ErrorSchangedEventArgs(nameof(Value1));
Value2=“B”;
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(nameof(Value2));
ErrorsChanged?.Invoke(这是新数据ErrorSchangedEventArgs(名称(值2));
}
}
看法
<Window ...>
<Window.DataContext>
<ViewModels:MainPresenter />
</Window.DataContext>
<DockPanel>
<Button Command="{Binding ResetValuesCommand}"
Margin="5" DockPanel.Dock="Top">Reset Values</Button>
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" Margin="5">
<DataGrid.Columns>
<DataGridTextColumn Header="Value 1"
Binding="{Binding Value1, ValidatesOnDataErrors=True}" />
<DataGridTextColumn Header="Value 2"
Binding="{Binding Value2, ValidatesOnDataErrors=True}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Window>
public class MainPresenter : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public IEnumerable<ItemPresenter> Items { get; }
= new ObservableCollection<ItemPresenter> {new ItemPresenter()};
public ICommand ResetValuesCommand => new ResetCommand(Items);
private class ResetCommand : ICommand
{
private readonly IEnumerable<ItemPresenter> _items;
public ResetCommand(IEnumerable<ItemPresenter> items) { _items = items; }
public void Execute(object parameter) => _items.ToList().ForEach(i => i.Reset());
public bool CanExecute(object parameter) => true;
public event EventHandler CanExecuteChanged { add { } remove { } }
}
}
public class ItemPresenter : INotifyPropertyChanged, IDataErrorInfo
{
public event PropertyChangedEventHandler PropertyChanged;
public string Value1 { get; set; } = "A";
public string Value2 { get; set; } = "B";
public string this[string columnName] => "ERROR";
public string Error => "ERROR";
public void Reset()
{
Value1 = "A";
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value1)));
Value2 = "B";
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value2)));
}
}
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" Margin="5">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Value 1">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
<TextBlock Text="{Binding Value1, ValidatesOnDataErrors=True}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
<TextBox Text="{Binding Value1, ValidatesOnDataErrors=True}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Value 2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
<TextBlock Text="{Binding Value2, ValidatesOnDataErrors=True}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
<TextBox Text="{Binding Value2, ValidatesOnDataErrors=True}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
public class ItemPresenter : INotifyPropertyChanged, INotifyDataErrorInfo
{
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public string Value1 { get; set; } = "A";
public string Value2 { get; set; } = "B";
public IEnumerable GetErrors(string propertyName) => new[] { "ERROR" };
public bool HasErrors => true;
public void Reset()
{
Value1 = "A";
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value1)));
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Value1)));
Value2 = "B";
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Value2)));
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Value2)));
}
}
<DataGrid ItemsSource="{Binding Items}" AutoGenerateColumns="False" Margin="5">
<DataGrid.Columns>
<DataGridTemplateColumn Header="Value 1">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
<TextBlock Text="{Binding Value1}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
<TextBox Text="{Binding Value1}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Value 2">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
<TextBlock Text="{Binding Value2}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate DataType="{x:Type ViewModels:ItemPresenter}">
<TextBox Text="{Binding Value2}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>