这是验证选定记录的正确方法吗?如果不是,正确的做法是什么?
不是。你做错了。
不可能给出完整的答案 - 它需要更多的实现代码。
因此,我正在写我可以从您的解释和部分代码中理解的内容。
是否需要验证单个 DataGrid 行的值,即当前选中的行。
并且接口IDataErrorInfo 很可能在集合级别(ViewModel)实现,而不是在元素本身。
因此,您希望查询到 "SelectedRecord.FirstName" 复合索引。
但是绑定不是这样工作的。
绑定中的路径仅指示如何沿该路径查找属性。
找到它后,绑定将直接使用属性本身,而不是为其搜索指定的路径。
因此,需要在用于表示字符串的类型中实现IDataErrorInfo。
并等待仅对该类型属性名称的请求"FirstName"。
用项目链接更新了我的问题
您的存储库没有完整的解决方案,因此我无法检查所做的更改 - 该项目不会被构建。
我将在这里描述需要进行的更改。
您自己添加它们,然后将您的整个解决方案添加到您的存储库中。
这样如果有错误,我可以重现它们。
-
删除 BaseViewModel 和 RelayCommand 类。它们的实现过于简单。将BaseInpc, RelayCommand, and RelayCommand classes 添加到项目中。
这些是更高级的实现。它们更易于使用并减少了一些错误的可能性。
-
视图模型:
using Simplified;
using System.Collections.ObjectModel;
namespace WpfApp1
{
public class ViewModel : BaseInpc
{
public ViewModel()
{
Names.Add(new Model { Id = 1, FirstName = "First Name 1", LastName = "Last Name 1" });
Names.Add(new Model { Id = 2, FirstName = "First Name 2", LastName = "Last Name 2" });
Names.Add(new Model { Id = 3, FirstName = "First Name 3", LastName = "Last Name 3" });
}
#region Properties
public ObservableCollection<Model> Names { get; } = new ObservableCollection<Model>();
private Model _selectedRecord;
public Model SelectedRecord
{
get => _selectedRecord;
set => Set(ref _selectedRecord, value);
}
#endregion
}
}
-
实体类。
我没有更改名称,因此您不会感到困惑,但这不是模型!
MVVM 中的模型是创建此实体实例的位置。实际上,创建 Names 集合的 ViewModel 代码部分就是您在 MVVM 中的模型。
using Simplified;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace WpfApp1
{
public class Model : BaseInpc, IDataErrorInfo
{
private int _id;
private string _firstName;
private string _lastName;
private string _error;
public int Id { get => _id; set => Set(ref _id, value); }
public string FirstName { get => _firstName; set => Set(ref _firstName, value); }
public string LastName { get => _lastName; set => Set(ref _lastName, value); }
#region IDataErrorInfo
public string Error { get => _error; private set => Set(ref _error, value); }
public Dictionary<string, string> ErrorCollection { get; } = new Dictionary<string, string>();
public string this[string propertyName]
{
get
{
if (string.IsNullOrWhiteSpace(propertyName))
return null;
string result = null;
switch (propertyName)
{
case nameof(FirstName):
if (string.IsNullOrWhiteSpace(FirstName))
result = "First Name cannot be empty";
break;
default:
break;
}
if (string.IsNullOrWhiteSpace(result))
ErrorCollection.Remove(propertyName);
else
ErrorCollection[propertyName] = result;
Error = string.Join(Environment.NewLine,
ErrorCollection.Where(pair => !string.IsNullOrWhiteSpace(pair.Value))
.Select(pair => $"{pair.Key}:\"{pair.Value}\""));
return result;
}
}
#endregion
}
}
-
窗口。
将数据上下文创建移至 XAML。自己构建Windows的XAML会更方便。
using System.Windows;
namespace WpfApp1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<FrameworkElement.DataContext>
<local:ViewModel/>
</FrameworkElement.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<DataGrid ItemsSource="{Binding Names}" SelectedItem="{Binding SelectedRecord}"/>
</Grid>
<StackPanel Grid.Column="1" DataContext="{Binding SelectedRecord}">
<Label Content="First Name" />
<TextBox Text="{Binding FirstName, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
<Label Content="Last Name" />
<TextBox Text="{Binding LastName, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>
</Grid>
</Window>