【问题标题】:How to validate DataGrid selected Item in WPF?如何验证 WPF 中的 DataGrid 选定项?
【发布时间】:2021-06-07 12:29:14
【问题描述】:

项目: https://github.com/98gzi/Validate-DataGrid-Selected-Item

目标

我的目标是单击数据网格行,获取所选项目值并将其绑定到文本框。所以我可以在那里编辑值,而不是直接在 DataGrid 中。

数据网格:

<DataGrid ItemsSource="{Binding List}" SelectedItem="{Binding SelectedRecord}" />

选择的记录显示的记录的属性到一个文本框:

<TextBox Text="{Binding SelectedRecord.FirstName}" />

这会正常工作,直到进行验证。

问题

我添加了以下代码来添加验证:

XAML

<TextBox Text="{Binding SelectedRecord.FirstName, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" />

查看模型验证

#region IDataErrorInfo
public string Error { get { return null; } }
public Dictionary<string, string> ErrorCollection { get; private set; } = new Dictionary<string, string>();
public string this[string propertyName]
{
    get
    {
        string result = null;

        switch (propertyName)
        {
            case "SelectedRecord.FirstName":
                if (string.IsNullOrWhiteSpace(SelectedRecord.FirstName))
                    result = "First Name cannot be empty";
                break;
            default:
                break;
        }

        if (ErrorCollection.ContainsKey(propertyName))
            ErrorCollection[propertyName] = result;
        else if (result != null)
            ErrorCollection.Add(propertyName, result);

        OnPropertyChanged(nameof(ErrorCollection));

        return result;
    }
}

#endregion

问题

这没有任何作用。即 UI 中没有显示错误,并且调试器也没有进入调试模式。

这是验证选定记录的正确方法吗?如果不是,正确的做法是什么?

【问题讨论】:

    标签: c# wpf validation


    【解决方案1】:

    这是验证选定记录的正确方法吗?如果不是,正确的做法是什么?

    不是。你做错了。

    不可能给出完整的答案 - 它需要更多的实现代码。
    因此,我正在写我可以从您的解释和部分代码中理解的内容。

    是否需要验证单个 DataGrid 行的值,即当前选中的行。
    并且接口IDataErrorInfo 很可能在集合级别(ViewModel)实现,而不是在元素本身。
    因此,您希望查询到 "SelectedRecord.FirstName" 复合索引。

    但是绑定不是这样工作的。

    绑定中的路径仅指示如何沿该路径查找属性。 找到它后,绑定将直接使用属性本身,而不是为其搜索指定的路径。

    因此,需要在用于表示字符串的类型中实现IDataErrorInfo
    并等待仅对该类型属性名称的请求"FirstName"

    用项目链接更新了我的问题

    您的存储库没有完整的解决方案,因此我无法检查所做的更改 - 该项目不会被构建。

    我将在这里描述需要进行的更改。 您自己添加它们,然后将您的整个解决方案添加到您的存储库中。 这样如果有错误,我可以重现它们。

    1. 删除 BaseViewModel 和 RelayCommand 类。它们的实现过于简单。将BaseInpc, RelayCommand, and RelayCommand classes 添加到项目中。 这些是更高级的实现。它们更易于使用并减少了一些错误的可能性。

    2. 视图模型:

    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
        }
    }
    
    1. 实体类。
      我没有更改名称,因此您不会感到困惑,但这不是模型! 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
    
        }
    }
    
    1. 窗口。
      将数据上下文创建移至 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>
    

    【讨论】:

    • 用项目链接更新了我的问题:)
    • 我在回答中添加了需要对您的项目进行哪些更改。
    【解决方案2】:

    激活 DataGrid 的 cell_click 事件处理程序。那么

        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            if (e.RowIndex >= 0)
            {
                DataGridViewRow row = this.dataGridView1.Rows[e.RowIndex];
                TextBox1.text = row.Cells["id_number"].Value.ToString();
            }
        }
    

    ** 将 textbox1.text 替换为您的文本框的 ID,将 dataGridView1 替换为您的数据网格 ID,并将“id_number”替换为您的数据网格列名称。

    【讨论】:

      猜你喜欢
      • 2015-10-15
      • 1970-01-01
      • 1970-01-01
      • 2012-12-09
      • 1970-01-01
      • 2023-03-16
      • 1970-01-01
      • 2018-09-06
      • 2011-09-29
      相关资源
      最近更新 更多