PageRenderTime 43ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/SourceGrid/SourceGrid.Extensions/DataGrid.cs

https://bitbucket.org/dariusdamalakas/sourcegrid/
C# | 582 lines | 425 code | 86 blank | 71 comment | 81 complexity | cd74525fabe5dc5e97cfa8b0b00d5cc0 MD5 | raw file
  1. using SourceGrid.Selection;
  2. using System;
  3. using System.Collections;
  4. using System.ComponentModel;
  5. using System.Drawing;
  6. using DevAge.ComponentModel;
  7. namespace SourceGrid
  8. {
  9. /// <summary>
  10. /// A grid control that support load from a System.Data.DataView class, usually used for data binding.
  11. /// </summary>
  12. [System.ComponentModel.ToolboxItem(true)]
  13. public class DataGrid : GridVirtual
  14. {
  15. public DataGrid()
  16. {
  17. FixedRows = 1;
  18. FixedColumns = 0;
  19. Controller.AddController(new DataGridCellController());
  20. SelectionMode = GridSelectionMode.Row;
  21. }
  22. protected override void Dispose(bool disposing)
  23. {
  24. base.Dispose (disposing);
  25. }
  26. /// <summary>
  27. /// Method used to create the rows object, in this class of type DataGridRows.
  28. /// </summary>
  29. protected override RowsBase CreateRowsObject()
  30. {
  31. return new DataGridRows(this);
  32. }
  33. /// <summary>
  34. /// Method used to create the columns object, in this class of type DataGridColumns.
  35. /// </summary>
  36. protected override ColumnsBase CreateColumnsObject()
  37. {
  38. return new DataGridColumns(this);
  39. }
  40. protected override SelectionBase CreateSelectionObject()
  41. {
  42. SourceGrid.Selection.SelectionBase selObj = base.CreateSelectionObject();
  43. selObj.EnableMultiSelection = false;
  44. selObj.FocusStyle = SourceGrid.FocusStyle.RemoveFocusCellOnLeave;
  45. selObj.FocusRowLeaving += new RowCancelEventHandler(Selection_FocusRowLeaving);
  46. return selObj;
  47. }
  48. private DevAge.ComponentModel.IBoundList mBoundList;
  49. public override bool EnableSort{
  50. get{
  51. if (DataSource == null)
  52. return false;
  53. return DataSource.AllowSort;
  54. }
  55. set
  56. {
  57. if (DataSource == null)
  58. return;
  59. DataSource.AllowSort = value;
  60. }
  61. }
  62. /// <summary>
  63. /// Gets or sets the IBoundList used for data binding.
  64. /// It can be any class that implements the IBoundList interface, usually can be BoundList
  65. /// (that can be used to bind to a generic List) or BoundDataView (that can be used to bind to a DataView).
  66. /// </summary>
  67. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  68. public DevAge.ComponentModel.IBoundList DataSource
  69. {
  70. get { return mBoundList; }
  71. set
  72. {
  73. Unbind();
  74. mBoundList = value;
  75. if (mBoundList != null)
  76. Bind();
  77. }
  78. }
  79. protected virtual void Unbind()
  80. {
  81. if (mBoundList != null)
  82. {
  83. mBoundList.ListChanged -= new ListChangedEventHandler(mBoundList_ListChanged);
  84. mBoundList.ItemDeleted -= new ItemDeletedEventHandler(mBoundList_ItemDeleted);
  85. mBoundList.ListCleared -= new EventHandler(mBoundList_ListCleared);
  86. }
  87. Rows.RowsChanged();
  88. }
  89. protected virtual void Bind()
  90. {
  91. if (Columns.Count == 0)
  92. CreateColumns();
  93. InvalidateDataGridColumns();
  94. mBoundList.ListChanged += new ListChangedEventHandler(mBoundList_ListChanged);
  95. mBoundList.ItemDeleted += new ItemDeletedEventHandler(mBoundList_ItemDeleted);
  96. mBoundList.ListCleared += new EventHandler(mBoundList_ListCleared);
  97. Rows.RowsChanged();
  98. Rows.ResetRowHeigth();
  99. }
  100. void mBoundList_ListCleared ( object sender, EventArgs e )
  101. {
  102. Rows.ResetRowHeigth();
  103. }
  104. void mBoundList_ItemDeleted ( object sender, DevAge.ComponentModel.ItemDeletedEventArgs e )
  105. {
  106. Rows.RowDeleted(e.Item);
  107. }
  108. private void InvalidateDataGridColumns()
  109. {
  110. foreach (DataGridColumn column in Columns)
  111. {
  112. column.Invalidate();
  113. }
  114. }
  115. /// <summary>
  116. /// Gets the rows information as a DataGridRows object.
  117. /// </summary>
  118. public new DataGridRows Rows
  119. {
  120. get{return (DataGridRows)base.Rows;}
  121. }
  122. /// <summary>
  123. /// Gets the columns informations as a DataGridColumns object.
  124. /// </summary>
  125. public new DataGridColumns Columns
  126. {
  127. get{return (DataGridColumns)base.Columns;}
  128. }
  129. protected virtual void mBoundList_ListChanged(object sender, ListChangedEventArgs e)
  130. {
  131. if (base.IsSuspended() == true)
  132. return;
  133. Rows.RowsChanged();
  134. Invalidate(true);
  135. }
  136. /// <summary>
  137. /// Gets a specified Cell by its row and column.
  138. /// </summary>
  139. /// <param name="p_iRow"></param>
  140. /// <param name="p_iCol"></param>
  141. /// <returns></returns>
  142. public override Cells.ICellVirtual GetCell(int p_iRow, int p_iCol)
  143. {
  144. if (mBoundList == null)
  145. return null;
  146. if (p_iCol >= Columns.Count)
  147. return null;
  148. if (p_iRow < FixedRows)
  149. return Columns[p_iCol].HeaderCell;
  150. else
  151. return Columns[p_iCol].GetDataCell(p_iRow);
  152. }
  153. protected override void OnSortingRangeRows(SortRangeRowsEventArgs e)
  154. {
  155. base.OnSortingRangeRows (e);
  156. if (DataSource == null || DataSource.AllowSort == false)
  157. return;
  158. System.ComponentModel.PropertyDescriptor propertyCol = Columns[e.KeyColumn].PropertyColumn;
  159. if (propertyCol != null)
  160. {
  161. ListSortDirection direction;
  162. if (e.Ascending)
  163. direction = ListSortDirection.Ascending;
  164. else
  165. direction = ListSortDirection.Descending;
  166. ListSortDescription[] sortsArray = new ListSortDescription[1];
  167. sortsArray[0] = new ListSortDescription(propertyCol, direction);
  168. DataSource.ApplySort(new ListSortDescriptionCollection(sortsArray));
  169. }
  170. else
  171. DataSource.ApplySort(null);
  172. }
  173. /// <summary>
  174. /// Automatic create the columns classes based on the specified DataSource.
  175. /// </summary>
  176. public void CreateColumns()
  177. {
  178. Columns.Clear();
  179. if (DataSource != null)
  180. {
  181. int i = 0;
  182. if (FixedColumns > 0)
  183. {
  184. Columns.Insert(i, DataGridColumn.CreateRowHeader(this));
  185. i++;
  186. }
  187. foreach (System.ComponentModel.PropertyDescriptor prop in DataSource.GetItemProperties())
  188. {
  189. Columns.Add(prop.Name,
  190. prop.DisplayName,
  191. SourceGrid.Cells.DataGrid.Cell.Create(prop.PropertyType, !prop.IsReadOnly));
  192. }
  193. }
  194. }
  195. /// <summary>
  196. /// Gets or sets the selected DataRowView.
  197. /// </summary>
  198. [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  199. public object[] SelectedDataRows
  200. {
  201. get
  202. {
  203. if (mBoundList == null)
  204. return new System.Data.DataRowView[0];
  205. int[] rowsSel = Selection.GetSelectionRegion().GetRowsIndex();
  206. int count = 0;
  207. for (int i = 0; i < rowsSel.Length; i++)
  208. {
  209. object objRow= Rows.IndexToDataSourceRow(rowsSel[i]);
  210. if (objRow != null)
  211. count++;
  212. }
  213. object[] dataRows = new object[count];
  214. int indexRows = 0;
  215. for (int i = 0; i < rowsSel.Length; i++)
  216. {
  217. object objRow = Rows.IndexToDataSourceRow(rowsSel[i]);
  218. if (objRow != null)
  219. {
  220. dataRows[indexRows] = objRow;
  221. indexRows++;
  222. }
  223. }
  224. return dataRows;
  225. }
  226. set
  227. {
  228. Selection.ResetSelection(false);
  229. if (mBoundList != null && value != null)
  230. {
  231. for (int i = 0; i < value.Length; i++)
  232. {
  233. for (int r = FixedRows; r < Rows.Count; r++)
  234. {
  235. object objRow = Rows.IndexToDataSourceRow(r);
  236. if (object.ReferenceEquals(objRow, value[i]))
  237. {
  238. Selection.SelectRow(r, true);
  239. break;
  240. }
  241. }
  242. }
  243. }
  244. }
  245. }
  246. protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
  247. {
  248. base.OnKeyDown(e);
  249. if (e.KeyCode == System.Windows.Forms.Keys.Delete &&
  250. mBoundList != null &&
  251. mBoundList.AllowDelete &&
  252. e.Handled == false &&
  253. mDeleteRowsWithDeleteKey)
  254. {
  255. object[] rows = SelectedDataRows;
  256. if (rows != null && rows.Length > 0)
  257. DeleteSelectedRows();
  258. e.Handled = true;
  259. }
  260. else if (e.KeyCode == System.Windows.Forms.Keys.Escape &&
  261. e.Handled == false &&
  262. mCancelEditingWithEscapeKey)
  263. {
  264. EndEditingRow(true);
  265. e.Handled = true;
  266. }
  267. }
  268. protected override void OnValidating(CancelEventArgs e)
  269. {
  270. base.OnValidating(e);
  271. try
  272. {
  273. if (EndEditingRowOnValidate)
  274. {
  275. EndEditingRow(false);
  276. }
  277. }
  278. catch (Exception ex)
  279. {
  280. OnUserException(new ExceptionEventArgs( ex ));
  281. }
  282. }
  283. private bool mEndEditingRowOnValidate = true;
  284. /// <summary>
  285. /// Gets or sets a property to force an End Editing when the control loose the focus
  286. /// </summary>
  287. [System.ComponentModel.DefaultValue(true)]
  288. public bool EndEditingRowOnValidate
  289. {
  290. get { return mEndEditingRowOnValidate; }
  291. set { mEndEditingRowOnValidate = value; }
  292. }
  293. private bool mDeleteRowsWithDeleteKey = true;
  294. /// <summary>
  295. /// Gets or sets if enable the delete of the selected rows when pressing Delete key.
  296. /// </summary>
  297. [System.ComponentModel.DefaultValue(true)]
  298. public bool DeleteRowsWithDeleteKey
  299. {
  300. get{return mDeleteRowsWithDeleteKey;}
  301. set{mDeleteRowsWithDeleteKey = value;}
  302. }
  303. private bool mCancelEditingWithEscapeKey = true;
  304. /// <summary>
  305. /// Gets or sets if enable the Cancel Editing feature when pressing escape key
  306. /// </summary>
  307. [System.ComponentModel.DefaultValue(true)]
  308. public bool CancelEditingWithEscapeKey
  309. {
  310. get{return mCancelEditingWithEscapeKey;}
  311. set{mCancelEditingWithEscapeKey = value;}
  312. }
  313. private string mDeleteQuestionMessage = "Are you sure to delete all the selected rows?";
  314. /// <summary>
  315. /// Message showed with the DeleteSelectedRows method. Set to null to not show any message.
  316. /// </summary>
  317. public string DeleteQuestionMessage
  318. {
  319. get{return mDeleteQuestionMessage;}
  320. set{mDeleteQuestionMessage = value;}
  321. }
  322. /// <summary>
  323. /// Delete all the selected rows.
  324. /// </summary>
  325. /// <returns>Returns true if one or more row is deleted otherwise false.</returns>
  326. public virtual bool DeleteSelectedRows()
  327. {
  328. if (string.IsNullOrEmpty(mDeleteQuestionMessage) ||
  329. System.Windows.Forms.MessageBox.Show(this, mDeleteQuestionMessage, System.Windows.Forms.Application.ProductName, System.Windows.Forms.MessageBoxButtons.YesNo, System.Windows.Forms.MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
  330. {
  331. foreach (int gridRow in Selection.GetSelectionRegion().GetRowsIndex())
  332. {
  333. int dataIndex = Rows.IndexToDataSourceIndex(gridRow);
  334. if (dataIndex < DataSource.Count)
  335. DataSource.RemoveAt(dataIndex);
  336. }
  337. return true;
  338. }
  339. return false;
  340. }
  341. /// <summary>
  342. /// AutoSize the columns based on the visible range and autosize the rows based on it's contents.
  343. /// </summary>
  344. public override void AutoSizeCells()
  345. {
  346. Columns.AutoSizeView();
  347. for ( int i = 0; i < Rows.Count; i++ )
  348. Rows.AutoSizeRow(i);
  349. }
  350. private void Selection_FocusRowLeaving(object sender, RowCancelEventArgs e)
  351. {
  352. try
  353. {
  354. EndEditingRow(false);
  355. }
  356. catch(Exception exc)
  357. {
  358. OnUserException(new ExceptionEventArgs(new EndEditingException( exc ) ) );
  359. e.Cancel = true;
  360. }
  361. }
  362. private int? mEditingRow;
  363. /// <summary>
  364. /// Check if the specified row is the active row (focused), return false if it is not the active row. Then call the BeginEdit on the associated DataRowView. Add a row to the DataView if required. Returns true if the method sucesfully call the BeginEdit and set the EditingRow property.
  365. /// </summary>
  366. /// <param name="gridRow"></param>
  367. /// <returns></returns>
  368. public bool BeginEditRow(int gridRow)
  369. {
  370. if (mEditingRow != null && mEditingRow.Value == gridRow)
  371. return true;
  372. EndEditingRow(false); //Terminate the old edit if present
  373. if (DataSource != null)
  374. {
  375. int dataIndex = Rows.IndexToDataSourceIndex(gridRow);
  376. // add this here to check if we have permission for edition
  377. if (!DataSource.AllowEdit)
  378. return false;
  379. if (dataIndex == DataSource.Count && DataSource.AllowNew) //Last Row
  380. {
  381. DataSource.BeginAddNew();
  382. }
  383. else if (dataIndex < DataSource.Count)
  384. {
  385. DataSource.BeginEdit(dataIndex);
  386. }
  387. }
  388. mEditingRow = gridRow;
  389. return true;
  390. }
  391. /// <summary>
  392. /// Calls the CancelEdit or the EndEdit on the editing Row and set to null the editing row.
  393. /// </summary>
  394. /// <param name="cancel"></param>
  395. public void EndEditingRow(bool cancel)
  396. {
  397. if (mBoundList != null)
  398. mBoundList.EndEdit(cancel);
  399. mEditingRow = null;
  400. }
  401. }
  402. #region Models
  403. /// <summary>
  404. /// A Model of type IValueModel used for binding the value to a specified property of the bound object.
  405. /// Used for the DataGrid control.
  406. /// </summary>
  407. public class DataGridValueModel : Cells.Models.IValueModel
  408. {
  409. /// <summary>
  410. /// Constructor
  411. /// </summary>
  412. public DataGridValueModel()
  413. {
  414. }
  415. #region IValueModel Members
  416. public object GetValue(CellContext cellContext)
  417. {
  418. DataGrid grid = (DataGrid)cellContext.Grid;
  419. PropertyDescriptor prop = grid.Columns[cellContext.Position.Column].PropertyColumn;
  420. int dataIndex = grid.Rows.IndexToDataSourceIndex(cellContext.Position.Row);
  421. //Check if the row is not outside the valid range (for example to handle the new row)
  422. if (dataIndex >= grid.DataSource.Count)
  423. return null;
  424. else
  425. return grid.DataSource.GetItemValue(dataIndex, prop);
  426. }
  427. public void SetValue(CellContext cellContext, object value)
  428. {
  429. DataGrid grid = (DataGrid)cellContext.Grid;
  430. PropertyDescriptor prop = grid.Columns[cellContext.Position.Column].PropertyColumn;
  431. object oldValue = GetValue(cellContext);
  432. ValueChangeEventArgs valArgs = new ValueChangeEventArgs(oldValue, value);
  433. if (cellContext.Grid != null)
  434. cellContext.Grid.Controller.OnValueChanging(cellContext, valArgs);
  435. grid.DataSource.SetEditValue(prop, valArgs.NewValue);
  436. if (cellContext.Grid != null)
  437. cellContext.Grid.Controller.OnValueChanged(cellContext, EventArgs.Empty);
  438. }
  439. #endregion
  440. }
  441. public class DataGridRowHeaderModel : Cells.Models.IValueModel
  442. {
  443. public DataGridRowHeaderModel()
  444. {
  445. }
  446. #region IValueModel Members
  447. public object GetValue(CellContext cellContext)
  448. {
  449. DataGrid dataGrid = (DataGrid)cellContext.Grid;
  450. if (dataGrid.DataSource != null &&
  451. dataGrid.DataSource.AllowNew &&
  452. cellContext.Position.Row == (dataGrid.Rows.Count - 1))
  453. return "*";
  454. else
  455. return null;
  456. }
  457. public void SetValue(CellContext cellContext, object p_Value)
  458. {
  459. throw new ApplicationException("Not supported");
  460. }
  461. #endregion
  462. }
  463. #endregion
  464. #region Controller
  465. public class DataGridCellController : Cells.Controllers.ControllerBase
  466. {
  467. public override void OnValueChanging(CellContext sender, ValueChangeEventArgs e)
  468. {
  469. base.OnValueChanging (sender, e);
  470. //BeginEdit on the row, set the Cancel = true if failed to start editing.
  471. bool success = ((DataGrid)sender.Grid).BeginEditRow(sender.Position.Row);
  472. if (success == false)
  473. throw new SourceGridException("Failed to editing row " + sender.Position.Row.ToString());
  474. }
  475. public override void OnEditStarting(CellContext sender, CancelEventArgs e)
  476. {
  477. base.OnEditStarting (sender, e);
  478. //BeginEdit on the row, set the Cancel = true if failed to start editing.
  479. bool success = ((DataGrid)sender.Grid).BeginEditRow(sender.Position.Row);
  480. e.Cancel = !success;
  481. }
  482. }
  483. #endregion
  484. [Serializable]
  485. public class EndEditingException : SourceGridException
  486. {
  487. public EndEditingException(Exception innerException):
  488. base(innerException.Message, innerException)
  489. {
  490. }
  491. protected EndEditingException(System.Runtime.Serialization.SerializationInfo p_Info, System.Runtime.Serialization.StreamingContext p_StreamingContext):
  492. base(p_Info, p_StreamingContext)
  493. {
  494. }
  495. }
  496. }