【问题标题】:Can I control when DataGridView reads and writes from/to its DataSource?我可以控制 DataGridView 何时从/向其 DataSource 读取和写入数据吗?
【发布时间】:2015-10-02 17:55:20
【问题描述】:

我绑定到List<MyCustomType>,当我在MyCustomType 的属性getter 上设置断点时,它们似乎被重复调用。是什么导致DataGridView 自动重新读取数据,我可以控制吗?

其次,我注意到当我对网格中的数据进行更改时,这些更改不会立即复制到 DataSource。在MyCustomType 中的属性设置器上设置断点,它们似乎只在我单击网格控件外部时被调用。如何确保在 GUI 中所做的更改立即应用于数据源?

【问题讨论】:

  • @Dylan 不,这是一个常规的 WinForms 项目
  • @Mr.Boy 如果您对解决方案有任何疑问,请告诉我 :)

标签: c# winforms datagridview .net-4.0


【解决方案1】:

重新读取您的属性是完全正常的,这是因为渲染。当DataGridView 渲染单元格时,它会从属性中读取。

支持INotifyPropertyChanged:

如果您想更改属性对DataGridView 可见,您应该实现INotifyPropertyChanged 以进行双向数据绑定。这会导致您的对象中的更改立即在网格中可见:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class Category : INotifyPropertyChanged
{
    #region Properties
    private int _Id;
    public int Id
    {
        get
        {
            return _Id;
        }
        set
        {
            if (_Id == value)
                return;
            _Id = value;
            OnPropertyChanged();
        }
    }

    private string _Name;
    public string Name
    {
        get
        {
            return _Name;
        }
        set
        {
            if (_Name == value)
                return;
            _Name = value;
            OnPropertyChanged();
        }
    }
    #endregion

    #region INotifyPropertyChanged
    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var eventHandler = this.PropertyChanged;
        if (eventHandler != null)
            eventHandler(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}
  • 如果您使用的是 .Net 4.5,请删除 [CallerMemberName] 并在调用 OnPropertyChanged 时只需传递属性名称,例如 OnPropertyChanged("Name")

使用BindingList

要更改对网格可见的列表,例如当您向数据列表添加新项目时,请使用 BindingList<T> 而不是 List<T>

如果您使用List<T>,则应将 DataSource 设置为 null 并再次设置为您的列表,以使更改对网格可见。

BindingList<Category> source = new BindingList<Category>();

private void Form_Load(object sender, EventArgs e)
{
    //Load Data to BindingList
    new List<Category>()
    {
        new Category(){Id=1, Name= "Category 1"},
        new Category(){Id=2, Name= "Category 2"},
    }.ForEach(x=>list.Add(x));

    this.categoryDataGridView.DataSource = list;
}

private void toolStripButton1_Click(object sender, EventArgs e)
{
    //Add data to BindingList 
    //Data will be visible to grid immediately
    list.Add(new Category(){Id=3, Name= "Category 3"});
}
  • 您还可以考虑将BindingList&lt;T&gt; 绑定到一个BindingSource 并将网格绑定到BindingSource。使用设计器时更有意义。

使用CurrentCellDirtyStateChanged

DataGridView 上的更改将自动应用于您的模型 OnValidating,但正如您还提到的,您可以使用网格的 CurrentCellDirtyStateChanged 事件来提交对数据源的更改。

private void categoryDataGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
    if (categoryDataGridView.IsCurrentCellDirty)
    {
        categoryDataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
    }
}
  • 我个人不建议所有列都使用这种技巧,例如假设您有一个字符串属性验证最小字符串长度为 5,现在如何输入 5 个字符,那么您将收到 5 个验证错误消息直到您输入 5 个字符。

仔细选择你需要的东西。

【讨论】:

  • 谢谢 - 但我可以控制何时完成验证,以便立即更新我的模型吗?我发现如果我切换复选框,模型只会在我点击不同的单元格时更新。我需要用户可见的内容来始终在用户更改某些内容时代表模型。
  • 我认为这个问题是#2 的答案,但我还没有测试过。 stackoverflow.com/questions/6468263/…
  • 嗨,我收到一个编译错误,[CallerMemberName] 未知...我需要特定的 using 参考或 .NET 版本吗?
  • @Mr.Boy using System.Runtime.CompilerServices; 和 .Net 4.5
  • @Mr.Boy 如果您使用.Net 4.0,只需删除该属性并将属性名称传递给方法,例如OnPropertyChanged("Name");
猜你喜欢
  • 1970-01-01
  • 2016-10-19
  • 2014-06-17
  • 2020-04-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多