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
作为DataGridView
的DataSource
最好在属性更改时得到通知以更新相应的项目。你可以这样做:
在您的 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