BindingList、DataGridView 和 SQL 过程

Posted

技术标签:

【中文标题】BindingList、DataGridView 和 SQL 过程【英文标题】:BindingList, DataGridView and SQL Procedures 【发布时间】:2013-09-30 06:49:48 【问题描述】:

我正在尝试构建简单的数据编辑器。 我创建了使用 DataGridView 编辑数据的简单应用程序。 为了保存我的数据对象,我使用了 BindingList。这样,在添加新项目后,我的网格就能够显示该新条目。 我的表单运行良好,但现在我必须将一些数据连接到它。 虽然加载很容易,但我在添加新元素和更新时遇到了问题。

我知道我可以使用 SqlDataAdapter 和 DataTable,但我想使用 BindingList 并使用存储过程自动保存所有更改。

我创建了一些模型类:

public class Phone : INotifyPropertyChanged

    #region AUTO
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    

    protected bool SetField<T>(ref T field, T value, string propertyName)
    
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    
    #endregion

    public int PhoneId  get; set; 
    public string Number  get; set; 
    public string Type  get; set; 
    public string TypeTxt  get; set; 

    private bool _valid;
    public bool Valid
    
        get  return _valid; 
        set  SetField(ref _valid, value, "Valid"); 
    

现在我只需要捕捉有效的变化,所以我只捕捉这个属性变化。

public class PhonesList : BindingList<Phone>

    public void AddNew(Phone newPhone)
    
        //here I could call my sql procedure
        Add(newPhone);
    

这个类存储我的手机,因为在 cmets 中我可以在 AddNew 方法中捕获 add,但是这样我必须使用 AddNew 而不是 Add

在我的主窗体中:

    private readonly int _userId;
    private PhonesList _phones;

    private BindingSource _gridSource;

    private BindingSource GridSource
    
        get  return _gridSource ?? (_gridSource = new BindingSource()); 
    

    public PhoneDetails(int userId)
    
        _userId = userId;
        InitializeComponent();
    

    private void PhoneDetails_Load(object sender, EventArgs e)
    
        if (_applicationId == 0) return;
        _phones = DB.Instance.LoadPhones(_userId);

        GridSource.DataSource = _phones;
        phonesGV.AutoGenerateColumns = false;
        phonesGV.DataSource = GridSource;
        _phones.ListChanged += _phones_ListChanged;
        _phones.RaiseListChangedEvents = true;
        _phones_ListChanged(null, null);
    

    void _phones_ListChanged(object sender, System.ComponentModel.ListChangedEventArgs e)
    
        Text = string.Format("Phones - count: 0", _phones.Count);
        Refresh();
    

    private void addNew_Click(object sender, EventArgs e)
    
        errorProvider1.Clear();
        if(newPhoneNumberTb.Text.Length<9)
        
            errorProvider1.SetError(newPhoneNumberTb,"9 digits minimum!");
            return;
        
        if (newPhoneTypeCb.SelectedItem==null)
        
            errorProvider1.SetError(newPhoneTypeCb, "Choose phone type!");
            return;
        
        _phones.AddNew(new Phone
            
                Number = newPhoneNumberTb.Text.Trim(),
                PhoneId = 0,
                Type = newPhoneTypeCb.SelectedItem.ToString(),
                TypeTxt = newPhoneTypeCb.SelectedItem.ToString(),
                Valid = true
            );
        newPhoneNumberTb.Text = "";
        newPhoneTypeCb.SelectedItem = null;
    

我可以使用存储过程将数据加载到我的表单中,但现在我想调用存储过程来添加新手机并在必要时更新它。

我应该在哪里监听添加/更新“事件”? 向模型添加添加/更新功能是否正确?

理想情况下,我可以向电话模型添加添加/更新,但这样我在加载数据时会遇到问题,因为每次创建实例时都会调用我的“添加”查询。

这是我的 LoadPhone:

    public PhonesList LoadPhones(int userId)
    
        var phones = new PhonesList();

        using (var conn = new SqlConnection(ConnStr))
        
            using (var cmd = new SqlCommand(@"LoadTelefonow", conn))
            
                cmd.Parameters.Add("@USER_ID", SqlDbType.Int).Value = userId;
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.CommandTimeout = 360;
                conn.Open();
                using (SqlDataReader sdr = cmd.ExecuteReader())
                
                    while (sdr.Read())
                    
                        var phone = new Phone
                        
                            PhoneId = Convert.ToInt32(sdr["Tel_Id"]),
                            Number = Convert.ToString(sdr["Number"]),
                            Type = Convert.ToString(sdr["Typ"]),
                            TypeTxt = Convert.ToString(sdr["Typ"]),
                            Valid = Convert.ToBoolean(sdr["Status"])
                        ;
                        phones.Add(phone);
                    
                
                conn.Close();
            
        
        return phones;
    

所以我的问题是:我应该在哪里以及如何向我的手机模型的 BindingList 添加添加和更新功能(不知道哪个更好)?

【问题讨论】:

【参考方案1】:

更新:

使用BindingSource 作为DataGridViewDataSource 最好在属性更改时得到通知以更新相应的项目。你可以这样做:

在您的 MainForm 中或通过设计器:

datagridview1.DataSource = bindingSource1;
bindingSource1.CurrentItemChanged += new EventHandler(bindingSource1_CurrentItemChanged);

在表单中声明一个字段以维护已更改项目的列表:

private List<int> UpdatedItemsIndex;

并在发生变化时添加:

private void bindingSource1_CurrentItemChanged(object sender, EventArgs e)

    UpdatedItemsIndex.Add(bindingSource1.IndexOf(bindingSource1.Current));

添加: 同样,使用 BindingSource 并处理 AddNew

bindingSource1.AddingNew += new System.ComponentModel.AddingNewEventHandler(this.bindingSource1_AddingNew);

还有:

List<int> AddedItemsIndex = new List<int>();
private void bindingSource1_AddingNew(object sender, AddingNewEventArgs e)

    AddedItemsIndex .Add(bindingSource1.Count);

保存更改:根据列表添加/更新。插入/更新后记得清除它们。

【讨论】:

我已经尝试过CurrentItemChanged,但是当我在网格中选择不同的行时它会触发,而不是当我更新行时(例如取消选中复选框列),我也尝试过AddingNew 但它没有开火。 CurrentItemChanged 在提交单元格的编辑时触发。例如,当您通过移动到另一个单元格或另一行离开该单元格时,它的更改就会提交。 AddingNew 应该会触发。 我无法让AddingNew 工作。 CurrentItemChanged 按照您的描述工作(我想它的工作方式不同,但现在很清楚)。可以将添加/更新功能添加到我的Phone 模型吗?这样,在我的应用程序的每个地方,我都可以更改属性,并且 db 中的正确行将自动更新。 可以。但是保留它是另一个故事,而不是控制交互

以上是关于BindingList、DataGridView 和 SQL 过程的主要内容,如果未能解决你的问题,请参考以下文章

C# 中 datagridview 绑定BindingList类型和更新

值更改时绑定到 BindingList 的 DataGridView 不刷新

从 BindingList 中删除最后一条记录选择最后一行导致 DataGridView 滚动

我的一些课 的成员不会出现绑定到BindingList的datagridview

使用BindingList来实现DataGridview数据源为list时的动态增删改

BindingList<> ListChanged 事件