利用EAP.Entity提供的可以Undo/Redo的列表绑定数据到DataGridView,让表格批量编辑更方便更高效。
1. 还是利用AccountGroup表的结构,然后得到实体AccountGroupModel:
1 [System.Serializable()] 2 public class AccountGroupModels : System.Collections.Generic.List<AccountGroupModel> 3 { 4 5 public AccountGroupModels() 6 { 7 } 8 9 public AccountGroupModels(System.Collections.Generic.IEnumerable<AccountGroupModel> collection) : 10 base(collection) 11 { 12 } 13 } 14 15 /// <summary> 16 /// <para></para> 17 /// </summary> 18 [System.Serializable()] 19 public partial class AccountGroupModel : EAP.Entity.DataObject<AccountGroupModel> 20 { 21 #region Member Property Region 22 /// <summary> 23 /// <para>主键</para> 24 /// </summary> 25 [EAP.Data.ColumnInfoAttribute(Visible = false, Queryable = true, DbColumn = "Id")] 26 public int Id 27 { 28 get 29 { 30 return GetValue<int>("Id"); 31 } 32 set 33 { 34 SetValue("Id", value); 35 } 36 } 37 38 /// <summary> 39 /// <para>名称</para> 40 /// </summary> 41 [EAP.Data.ColumnInfoAttribute(DbColumn = "Name")] 42 public string Name 43 { 44 get 45 { 46 return GetValue<string>("Name"); 47 } 48 set 49 { 50 SetValue("Name", value); 51 } 52 } 53 54 /// <summary> 55 /// <para>上级组别</para> 56 /// </summary> 57 [EAP.Data.ColumnInfoAttribute(DbColumn = "Parent")] 58 public int Parent 59 { 60 get 61 { 62 return GetValue<int>("Parent"); 63 } 64 set 65 { 66 SetValue("Parent", value); 67 } 68 } 69 70 /// <summary> 71 /// <para>可见性</para> 72 /// </summary> 73 [EAP.Data.ColumnInfoAttribute(DbColumn = "Visible")] 74 public bool Visible 75 { 76 get 77 { 78 return GetValue<bool>("Visible"); 79 } 80 set 81 { 82 SetValue("Visible", value); 83 } 84 } 85 86 /// <summary> 87 /// <para>修改者</para> 88 /// </summary> 89 [EAP.Data.ColumnInfoAttribute(DbColumn = "UpdateUser")] 90 public string UpdateUser 91 { 92 get 93 { 94 return GetValue<string>("UpdateUser"); 95 } 96 set 97 { 98 SetValue("UpdateUser", value); 99 } 100 } 101 102 /// <summary> 103 /// <para>修改时间</para> 104 /// </summary> 105 [EAP.Data.ColumnInfoAttribute(DbColumn = "UpdateDate")] 106 public System.DateTime UpdateDate 107 { 108 get 109 { 110 return GetValue<System.DateTime>("UpdateDate"); 111 } 112 set 113 { 114 SetValue("UpdateDate", value); 115 } 116 } 117 #endregion 118 }
2. 定义业务接口:
1 interface IAccountGroupManager 2 { 3 /// <summary> 4 /// 加载Models 5 /// </summary> 6 /// <param name="name"></param> 7 /// <returns></returns> 8 AccountGroupModels GetModels(string name); 9 /// <summary> 10 /// 保存 11 /// </summary> 12 /// <param name="models">需要保存的列表</param> 13 /// <param name="user">更新者</param> 14 void Save(List<AccountGroupModel> models, string user); 15 /// <summary> 16 /// 加载所有可见的账户组 17 /// </summary> 18 /// <returns></returns> 19 ValueTextList GetGroupList(); 20 }
3. GetModels方法的实现
1 public AccountGroupModels GetModels(string name) 2 { 3 AccountGroupTable table = new AccountGroupTable(); 4 SelectStatement sql = DataAccess.DefaultDB 5 .Select(table, table.AllColumns())//读取所有字段 6 .OrderBy(table.UpdateDate.Desc);//按修改时间倒序 7 if (!name.IsNullOrEmpty())//如果名称不为空,添加模糊查询条件 8 sql.Where(table.Name.Like("%" + name + "%")); 9 using (SafeDataReader sdr = sql.ToSafeDataReader()) 10 { 11 AccountGroupModels models = new AccountGroupModels(); 12 while (sdr.Read()) 13 { 14 AccountGroupModel m = new AccountGroupModel(); 15 m.BeginInit();//把model的状态设为Initializing,修改值时不会触发什么事件 16 sdr.Fetch(m, table);//把数据加载到model 17 m.EndInit(); 18 models.Add(m); 19 } 20 return models; 21 } 22 }
4. Save方法的实现
1 public void Save(List<AccountGroupModel> models, string user) 2 { 3 Validator v = new Validator();//构建验证器 4 using (DbTransaction tran = DataAccess.DefaultDB.BeginTransaction())//开始事务 5 { 6 foreach (var m in models) 7 { 8 CheckModel(v, m, tran);//验证数据 9 m.UpdateUser = user; 10 m.UpdateDate = System.DateTime.Now; 11 if (m.DataState == DataState.Created) 12 AddModel(m, tran); 13 else if (m.DataState == DataState.Modified) 14 UpdateModel(m, tran); 15 else if (m.DataState == DataState.Deleted) 16 DeleteModel(m, tran); 17 } 18 if (!v.IsValid)//验证不通过时抛出异常 19 throw new ValidationException(v); 20 tran.Commit(); 21 } 22 }
5. CheckModel方法
1 protected bool Exists(AccountGroupModel model, DbTransaction tran) 2 { 3 AccountGroupTable table = new AccountGroupTable(); 4 SelectStatement sql = DataAccess.DefaultDB 5 .Select(table, table.AllColumns(false).Count()) 6 .SetTransaction(tran) 7 .Where(table.Name == model.Name); 8 if (model.DataState != EAP.Entity.DataState.Created) 9 sql.Where(table.Id != model.Id); 10 return sql.ToScalar<int>() > 0; 11 } 12 13 protected void CheckModel(Validator v, AccountGroupModel model, DbTransaction tran) 14 { 15 //名称不能为空,长度不能超过64字符 16 if (v.Require(model.Name, "Name", model.DisplayIndex) 17 && v.MaxLength(model.Name, 64, "Name", model.DisplayIndex)) 18 { 19 //名称不能重复 20 v.Assert(!Exists(model, tran), "Name", model.DisplayIndex, ErrorText.Exists); 21 } 22 v.MaxLength(model.UpdateUser, 32, "UpdateUser", model.DisplayIndex); 23 }
6. 窗口中的代码
1 public partial class DemoForm : KryptonForm 2 { 3 //业务接口 4 IAccountGroupManager manager; 5 //实体列表 6 DataObjectList<AccountGroupModel> models = new DataObjectList<AccountGroupModel>(); 7 8 public DemoForm() 9 { 10 InitializeComponent(); 11 //创建接口的实现 12 manager = new RefObjectCreator().Create<IAccountGroupManager>(); 13 //把实体绑定到BindingSource 14 accountGroupModelBindingSource.DataSource = models; 15 models.ListChanged += new EventHandler<ListChangedEventArgs<AccountGroupModel>>(models_ListChanged); 16 CancelEdit(); 17 } 18 19 void models_ListChanged(object sender, ListChangedEventArgs<AccountGroupModel> e) 20 { 21 btnUndo.Enabled = models.CanUndo; 22 btnRedo.Enabled = models.CanRedo; 23 btnSave.Enabled = models.HasChanged; 24 } 25 26 void LoadData() 27 { 28 //加载上级组别的数据 29 ValueTextList parent = manager.GetGroupList(); 30 parent.Insert(0, new ValueTextPair(0, "")); 31 parentBindingSource.DataSource = parent; 32 //加载实现的数据 33 AccountGroupModels source = manager.GetModels(txtName.Text); 34 models.Clear(); 35 models.BeginInit();//加载时不触发绑定的事件 36 models.AddRange(source); 37 models.EndInit(); 38 accountGroupModelBindingSource.ResetBindings(false); 39 CancelEdit(); 40 } 41 42 void BeginEdit() 43 { 44 models.BeginEdit(); 45 grid.ReadOnly = false; 46 btnNew.Enabled = true; 47 btnDelete.Enabled = true; 48 btnEdit.Enabled = false; 49 btnCancel.Enabled = true; 50 grid.StateNormal.DataCell.Back.Color1 = Color.Empty; 51 idDataGridViewTextBoxColumn.ReadOnly = true; 52 updateDateDataGridViewTextBoxColumn.ReadOnly = true; 53 updateUserDataGridViewTextBoxColumn.ReadOnly = true; 54 } 55 56 void CancelEdit() 57 { 58 models.CancelEdit(); 59 grid.ReadOnly = true; 60 btnNew.Enabled = false; 61 btnDelete.Enabled = false; 62 btnSave.Enabled = false; 63 btnUndo.Enabled = false; 64 btnRedo.Enabled = false; 65 btnEdit.Enabled = true; 66 btnCancel.Enabled = false; 67 pnlErrorInfo.Visible = false; 68 grid.StateNormal.DataCell.Back.Color1 = SystemColors.Info; 69 accountGroupModelBindingSource.ResetBindings(false); 70 } 71 72 #region 工具条按钮事件 73 74 private void btnSearch_Click(object sender, EventArgs e) 75 { 76 LoadData(); 77 } 78 79 private void btnClear_Click(object sender, EventArgs e) 80 { 81 txtName.Clear(); 82 } 83 84 private void btnEdit_Click(object sender, EventArgs e) 85 { 86 BeginEdit(); 87 } 88 89 private void btnCancel_Click(object sender, EventArgs e) 90 { 91 CancelEdit(); 92 } 93 94 private void btnSave_Click(object sender, EventArgs e) 95 { 96 try 97 { 98 grid.EndEdit(); 99 pnlErrorInfo.Visible = false;//隐藏错误信息 100 foreach (DataGridViewRow r in grid.Rows) 101 { 102 foreach (DataGridViewCell c in r.Cells) 103 c.ErrorText = ""; 104 } 105 //获取需要保存的实体列表 106 List<AccountGroupModel> changed = models.GetChangedItems(); 107 manager.Save(changed, "Demo"); 108 LoadData(); 109 } 110 catch (Exception exc) 111 { 112 if (exc is ValidationException)//显示验证的异常信息 113 { 114 pnlErrorInfo.Visible = true; 115 lblErrorInfo.Text = ""; 116 ValidationException ve = (ValidationException)exc; 117 foreach (ErrorInfo error in ve.ErrorInfos) 118 { 119 if (error.RowNum > -1) 120 { 121 string text = error.Errors.ToString(); 122 grid.Rows[error.RowNum].Cells[FindColumn(grid, error.FiledName).Name] 123 .ErrorText = text; 124 lblErrorInfo.Text += "[Row:" + (error.RowNum + 1) + "] " 125 + error.FiledName + ":" + text + ";\r\n"; 126 } 127 } 128 } 129 else 130 MessageBox.Show(exc.ToString(), "Error"); 131 } 132 } 133 134 private void btnNew_Click(object sender, EventArgs e) 135 { 136 accountGroupModelBindingSource.AddNew(); 137 } 138 139 private void btnDelete_Click(object sender, EventArgs e) 140 { 141 if (grid.SelectedRows.Count > 0) 142 { 143 foreach (DataGridViewRow row in grid.SelectedRows) 144 accountGroupModelBindingSource.Remove(row.DataBoundItem); 145 } 146 else if (accountGroupModelBindingSource.Current != null) 147 accountGroupModelBindingSource.Remove(accountGroupModelBindingSource.Current); 148 149 } 150 151 private void btnUndo_Click(object sender, EventArgs e) 152 { 153 grid.EndEdit(); 154 if (models.CanUndo)//撤销 155 SetFocused(models.Undo()); 156 } 157 158 private void btnRedo_Click(object sender, EventArgs e) 159 { 160 grid.EndEdit(); 161 if (models.CanRedo)//恢复 162 SetFocused(models.Redo()); 163 } 164 165 #endregion 166 167 /// <summary> 168 /// 聚焦到发生变化的行或者单元格 169 /// </summary> 170 /// <param name="edited"></param> 171 void SetFocused(EditedObject<AccountGroupModel> edited) 172 { 173 accountGroupModelBindingSource.ResetBindings(false); 174 grid.ClearSelection(); 175 if (edited.NewState == DataState.Modified) 176 { 177 int index = models.IndexOf(edited.DataObject); 178 grid.Rows[index].Cells[FindColumn(grid, edited.PropertyName).Name].Selected = true; 179 } 180 else 181 { 182 int index = models.IndexOf(edited.DataObject); 183 if (index != -1) 184 grid.Rows[index].Selected = true; 185 } 186 } 187 188 private DataGridViewColumn FindColumn(DataGridView grid, string property) 189 { 190 //根据属性名查找DataGridViewColumn 191 foreach (DataGridViewColumn col in grid.Columns) 192 { 193 if (col.DataPropertyName == property) 194 return col; 195 } 196 return null; 197 } 198 199 private void grid_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e) 200 { 201 int index = 1; 202 foreach (DataGridViewRow r in grid.Rows)//显示表格的行号 203 r.HeaderCell.Value = index++; 204 } 205 }
7. 运行结果
示例代码下载EntityDemo.zip