GridControlEx.cs 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. using DevExpress.Utils;
  2. using DevExpress.Utils.Helpers;
  3. using DevExpress.Utils.Menu;
  4. using DevExpress.Utils.Paint;
  5. using DevExpress.Utils.Svg;
  6. using DevExpress.XtraBars;
  7. using DevExpress.XtraEditors;
  8. using DevExpress.XtraEditors.Controls;
  9. using DevExpress.XtraEditors.Repository;
  10. using DevExpress.XtraGrid;
  11. using DevExpress.XtraGrid.Columns;
  12. using DevExpress.XtraGrid.Views.Grid;
  13. using DxHelper;
  14. using System;
  15. using System.Collections.Generic;
  16. using System.Drawing;
  17. using System.IO;
  18. using System.Linq;
  19. using System.Text;
  20. using System.Threading.Tasks;
  21. using System.Windows.Forms;
  22. public static class GridControlEx
  23. {
  24. internal class GridTag
  25. {
  26. public GridTag() { }
  27. public PopupMenu PopupMenu { get; set; }
  28. public BarManager BarM { get; set; }
  29. public List<BarButtonItem> RowButtonsItems { get; set; } = new List<BarButtonItem>();
  30. public List<BarButtonItem> MultRowButtonsItems { get; set; } = new List<BarButtonItem>();
  31. }
  32. /// <summary>
  33. /// 初始化表格(默认禁用分组)
  34. /// </summary>
  35. /// <param name="grid"></param>
  36. /// <param name="dataSource">绑定的数据源</param>
  37. /// <param name="rowHeight">行高(默认24px)</param>
  38. /// <param name="showScrollH">是否显示水平滚动条(默认不显示)</param>
  39. /// <typeparam name="T">绑定的数据源模型类型</typeparam>
  40. /// <returns></returns>
  41. public static GridControl UseDefault<T>(this GridControl grid, List<T> dataSource, int rowHeight = 24, bool showScrollH = false)
  42. {
  43. grid.DataSource = dataSource;
  44. grid.MainView.BorderStyle = BorderStyles.Flat;
  45. var view = grid.MainView as GridView;
  46. view.CustomColumnDisplayText += View_CustomColumnDisplayText;
  47. view.Appearance.HeaderPanel.TextOptions.HAlignment = HorzAlignment.Center;
  48. view.Appearance.Row.Options.UseTextOptions = true;
  49. view.Appearance.Row.TextOptions.HAlignment = HorzAlignment.Center;
  50. view.OptionsView.ColumnHeaderAutoHeight = DefaultBoolean.True;
  51. view.RowHeight = rowHeight;
  52. view.OptionsView.ShowGroupPanel = false;
  53. view.OptionsBehavior.Editable = false;
  54. view.OptionsView.ShowDetailButtons = false;
  55. view.OptionsView.ShowIndicator = false;
  56. view.OptionsMenu.EnableColumnMenu = true;
  57. view.OptionsCustomization.AllowFilter = true;
  58. view.OptionsCustomization.AllowGroup = false;
  59. view.OptionsCustomization.AllowSort = true;
  60. view.OptionsCustomization.AllowColumnMoving = true;
  61. view.OptionsCustomization.AllowMergedGrouping = DefaultBoolean.False;
  62. view.OptionsSelection.MultiSelect = false;
  63. view.OptionsCustomization.AllowRowSizing = false;
  64. view.OptionsCustomization.AllowQuickHideColumns = false;
  65. view.OptionsMenu.EnableGroupPanelMenu = false;
  66. view.OptionsMenu.EnableGroupRowMenu = false;
  67. view.OptionsMenu.EnableFooterMenu = false;
  68. view.OptionsLayout.StoreAllOptions = true;
  69. view.OptionsLayout.StoreAppearance = true;
  70. view.OptionsLayout.StoreDataSettings = true;
  71. view.OptionsLayout.StoreVisualOptions = true;
  72. view.OptionsLayout.StoreFormatRules = true;
  73. view.OptionsView.ColumnAutoWidth = !showScrollH;
  74. view.PopupMenuShowing += View_PopupMenuShowing;
  75. view.OptionsSelection.EnableAppearanceFocusedCell = false;
  76. string GetLayoutName()
  77. {
  78. Control ctrl;
  79. if (view.Tag is SearchLookUpEdit searchLookUpEdit)
  80. ctrl = searchLookUpEdit;
  81. else
  82. ctrl = grid;
  83. while (ctrl.Parent != null)
  84. {
  85. ctrl = ctrl.Parent;
  86. if (ctrl is UserControl) break;
  87. }
  88. var props = typeof(T).GetProperties();
  89. StringBuilder sb = new StringBuilder();
  90. foreach (var item in props)
  91. {
  92. sb.Append(item.Name);
  93. }
  94. var md5 = MD5Helper.StrToMD5(sb.ToString());
  95. if (view.Tag is SearchLookUpEdit searchLookUpEdit2)
  96. return $"{ctrl.Name}_{searchLookUpEdit2.Name}_{md5}";
  97. else
  98. return $"{ctrl.Name}_{grid.Name}_{md5}";
  99. }
  100. string name = GetLayoutName();
  101. void SaveLayoutAction()
  102. {
  103. Form frm = null;
  104. if (view.Tag is SearchLookUpEdit edit)
  105. frm = edit.FindForm();
  106. else
  107. frm = grid.FindForm();
  108. if (frm != null)
  109. {
  110. frm.VisibleChanged += (sender2, e2) =>
  111. {
  112. Directory.CreateDirectory("Layout");
  113. if (name == null) return;
  114. grid.MainView?.SaveLayoutToXml($"Layout\\{name}.xml", OptionsLayoutBase.FullLayout);
  115. };
  116. }
  117. }
  118. if (grid.IsLoaded)
  119. {
  120. SaveLayoutAction();
  121. }
  122. else
  123. {
  124. grid.Load += (sender, e) => SaveLayoutAction();
  125. }
  126. if (name != null && File.Exists($"Layout\\{name}.xml"))
  127. {
  128. view.RestoreLayoutFromXml($"Layout\\{name}.xml", OptionsLayoutBase.FullLayout);
  129. view.ClearColumnsFilter();
  130. view.ClearFindFilter();
  131. view.ClearInHeaderSearchText();
  132. view.ClearSorting();
  133. view.ClearSelection();
  134. }
  135. view.KeyUp += View_KeyUp;
  136. grid.Tag = new GridTag();
  137. return grid;
  138. }
  139. /// <summary>
  140. /// 为GirdControl启用右键新增数据的功能
  141. /// </summary>
  142. /// <param name="grid"></param>
  143. /// <param name="emptyText"></param>
  144. /// <returns></returns>
  145. public static GridControl UseEmptyText(this GridControl grid, string emptyText = "暂无数据")
  146. {
  147. if (string.IsNullOrWhiteSpace(emptyText)) return grid;
  148. var view = grid.MainView as GridView;
  149. view.CustomDrawEmptyForeground += (sender, e) =>
  150. {
  151. var s = e.Appearance.CalcTextSize(e.Cache, emptyText, e.Bounds.Width).ToSize();
  152. var x = (e.Bounds.Width - s.Width) / 2;
  153. var y = (e.Bounds.Height - s.Height) / 2;
  154. e.Appearance.ForeColor = Color.Gray;
  155. e.Appearance.DrawString(e.Cache, emptyText, new Rectangle(x, y, s.Width, s.Height));
  156. };
  157. return grid;
  158. }
  159. /// <summary>
  160. /// 为GirdControl启用右键新增数据的功能
  161. /// </summary>
  162. /// <typeparam name="T"></typeparam>
  163. /// <param name="grid"></param>
  164. /// <param name="menuCaption"></param>
  165. /// <param name="callback">一个回调函数,返回新增的数据</param>
  166. /// <returns></returns>
  167. public static GridControl UseAdd<T>(this GridControl grid, Func<T> callback, string menuCaption = "新增")
  168. {
  169. var view = grid.MainView as GridView;
  170. view.CustomDrawEmptyForeground += (sender, e) =>
  171. {
  172. string emptyText = "右键添加";
  173. var s = e.Appearance.CalcTextSize(e.Cache, emptyText, e.Bounds.Width).ToSize();
  174. var x = (e.Bounds.Width - s.Width) / 2;
  175. var y = (e.Bounds.Height - s.Height) / 2;
  176. e.Appearance.ForeColor = Color.Gray;
  177. e.Appearance.DrawString(e.Cache, emptyText, new Rectangle(x, y, s.Width, s.Height));
  178. };
  179. grid.AddContentMenu<T>(menuCaption, DxHelper.SvgHelper.CreateAdd(), data =>
  180. {
  181. if (callback != null)
  182. {
  183. var addRow = callback();
  184. if (addRow == null) return;
  185. var ds = grid.DataSource as List<T>;
  186. ds.Add(addRow);
  187. view.RefreshData();
  188. }
  189. }, true);
  190. return grid;
  191. }
  192. /// <summary>
  193. /// 为GirdControl启用右键新增数据的功能
  194. /// </summary>
  195. /// <typeparam name="T"></typeparam>
  196. /// <param name="grid"></param>
  197. /// <param name="menuCaption"></param>
  198. /// <param name="callback">一个回调函数,返回新增的数据</param>
  199. /// <returns></returns>
  200. public static GridControl UseAddAsync<T>(this GridControl grid, Func<Task<T>> callback, string menuCaption = "新增")
  201. {
  202. grid.AddContentMenuAsync<T>(menuCaption, DxHelper.SvgHelper.CreateAdd(), async data =>
  203. {
  204. if (callback != null)
  205. {
  206. var addRow = await callback();
  207. if (addRow == null) return;
  208. var view = grid.MainView as GridView;
  209. var ds = grid.DataSource as List<T>;
  210. ds.Add(addRow);
  211. view.RefreshData();
  212. }
  213. }, true);
  214. return grid;
  215. }
  216. /// <summary>
  217. /// 为GridControl启用右编辑选中的单行功能
  218. /// </summary>
  219. /// <typeparam name="T"></typeparam>
  220. /// <param name="grid"></param>
  221. /// <param name="menuCaption"></param>
  222. /// <param name="callback"></param>
  223. /// <returns></returns>
  224. public static GridControl UseEdit<T>(this GridControl grid, Func<T, T> callback, string menuCaption = "编辑")
  225. {
  226. grid.AddRowMenu<T>(menuCaption, DxHelper.SvgHelper.CreateEdit(), data =>
  227. {
  228. if (callback != null)
  229. {
  230. var newRow = callback(data);
  231. if (newRow == null) return;
  232. var view = grid.MainView as GridView;
  233. var ds = grid.DataSource as List<T>;
  234. var idx = ds.IndexOf(data);
  235. ds.Remove(data);
  236. ds.Insert(idx, newRow);
  237. view.RefreshData();
  238. }
  239. }, null);
  240. return grid;
  241. }
  242. /// <summary>
  243. /// 为GridControl启用右编辑选中的单行功能
  244. /// </summary>
  245. /// <typeparam name="T"></typeparam>
  246. /// <param name="grid"></param>
  247. /// <param name="menuCaption"></param>
  248. /// <param name="callback"></param>
  249. /// <returns></returns>
  250. public static GridControl UseEditAsync<T>(this GridControl grid, Func<T, Task<T>> callback, string menuCaption = "编辑")
  251. {
  252. grid.AddRowMenu<T>(menuCaption, DxHelper.SvgHelper.CreateEdit(), async data =>
  253. {
  254. if (callback != null)
  255. {
  256. var newRow = await callback(data);
  257. if (newRow == null) return;
  258. var view = grid.MainView as GridView;
  259. var ds = grid.DataSource as List<T>;
  260. var idx = ds.IndexOf(data);
  261. ds.Remove(data);
  262. ds.Insert(idx, newRow);
  263. view.RefreshData();
  264. }
  265. }, null);
  266. return grid;
  267. }
  268. /// <summary>
  269. /// 为GridControl启用右删除选中的一行或多行功能(自动启用UseMultiSelect)
  270. /// </summary>
  271. /// <typeparam name="T"></typeparam>
  272. /// <param name="grid"></param>
  273. /// <param name="menuCaption"></param>
  274. /// <param name="action"></param>
  275. /// <returns></returns>
  276. public static GridControl UseDelete<T>(this GridControl grid, Func<List<T>, bool> action = null, string menuCaption = "删除")
  277. {
  278. grid.AddMultRowMenu<T>(menuCaption, DxHelper.SvgHelper.CreateClose(), data =>
  279. {
  280. if (!DxHelper.MsgBoxHelper.ShowConfirm($"确认删除选中的记录?共[{data.Count}]条")) return;
  281. if (action != null)
  282. {
  283. bool succeed = action(data);
  284. if (!succeed) return;
  285. }
  286. var view = grid.MainView as GridView;
  287. view.DeleteSelectedRows();
  288. view.RefreshData();
  289. });
  290. return grid;
  291. }
  292. /// <summary>
  293. /// 为GridControl启用右删除选中的一行或多行功能(自动启用UseMultiSelect)
  294. /// </summary>
  295. /// <typeparam name="T"></typeparam>
  296. /// <param name="grid"></param>
  297. /// <param name="menuCaption"></param>
  298. /// <param name="action"></param>
  299. /// <returns></returns>
  300. public static GridControl UseDeleteAsync<T>(this GridControl grid, Func<List<T>, Task<bool>> action = null, string menuCaption = "删除")
  301. {
  302. grid.AddMultRowMenu<T>(menuCaption, DxHelper.SvgHelper.CreateClose(), async data =>
  303. {
  304. if (!DxHelper.MsgBoxHelper.ShowConfirm($"确认删除选中的记录?共[{data.Count()}]条")) return;
  305. if (action != null)
  306. {
  307. bool succeed = await action(data);
  308. if (!succeed) return;
  309. }
  310. var view = grid.MainView as GridView;
  311. view.DeleteSelectedRows();
  312. view.RefreshData();
  313. });
  314. return grid;
  315. }
  316. /// <summary>
  317. /// 为GirdControl启用右键清除所有数据的功能
  318. /// </summary>
  319. /// <typeparam name="T"></typeparam>
  320. /// <param name="grid"></param>
  321. /// <param name="menuCaption"></param>
  322. /// <param name="action"></param>
  323. /// <returns></returns>
  324. public static GridControl UseClear<T>(this GridControl grid, Func<List<T>, bool> action = null, string menuCaption = "清除")
  325. {
  326. grid.AddContentMenu<T>(menuCaption, DxHelper.SvgHelper.CreateClear(), data =>
  327. {
  328. if (data == null || data.Count == 0) return;
  329. if (!DxHelper.MsgBoxHelper.ShowConfirm($"确认清空所有记录?共[{data.Count}]条")) return;
  330. if (action != null)
  331. {
  332. bool succeed = action(data);
  333. if (!succeed) return;
  334. }
  335. var view = grid.MainView as GridView;
  336. data.Clear();
  337. view.RefreshData();
  338. }, false);
  339. return grid;
  340. }
  341. public static GridControl SetLogImageColumn(this GridControl grid, string columnFieldName,Type enumType)
  342. {
  343. var view = grid.MainView as GridView;
  344. RepositoryItemImageComboBox edit = new RepositoryItemImageComboBox();
  345. edit.AddEnum(enumType);
  346. SvgImageCollection svgImages = new SvgImageCollection();
  347. svgImages.ImageSize = new System.Drawing.Size(20, 20);
  348. svgImages.Add(SvgHelper.CreateInfo());
  349. svgImages.Add(SvgHelper.CreateWarning());
  350. svgImages.Add(SvgHelper.CreateError());
  351. edit.SmallImages = svgImages;
  352. edit.GlyphAlignment = DevExpress.Utils.HorzAlignment.Center;
  353. view.Columns[columnFieldName].ColumnEdit = edit;
  354. return grid;
  355. }
  356. /// <summary>
  357. /// 为GirdControl启用右键清除所有数据的功能
  358. /// </summary>
  359. /// <typeparam name="T"></typeparam>
  360. /// <param name="grid"></param>
  361. /// <param name="menuCaption"></param>
  362. /// <param name="action"></param>
  363. /// <returns></returns>
  364. public static GridControl UseClearAsync<T>(this GridControl grid, Func<List<T>, Task<bool>> action = null, string menuCaption = "清除")
  365. {
  366. grid.AddContentMenu<T>(menuCaption, DxHelper.SvgHelper.CreateClear(), async data =>
  367. {
  368. if (data == null || data.Count == 0) return;
  369. if (!DxHelper.MsgBoxHelper.ShowConfirm($"确认清空所有记录?共[{data.Count}]条")) return;
  370. if (action != null)
  371. {
  372. bool succeed = await action(data);
  373. if (!succeed) return;
  374. }
  375. var view = grid.MainView as GridView;
  376. data.Clear();
  377. view.RefreshData();
  378. }, false);
  379. return grid;
  380. }
  381. public static GridControl UseExportCsv(this GridControl grid)
  382. {
  383. GridTag tag = grid.Tag as GridTag;
  384. if (tag.BarM == null)
  385. {
  386. tag.BarM = new BarManager();
  387. tag.BarM.Form = grid;
  388. }
  389. if (tag.PopupMenu == null)
  390. {
  391. tag.PopupMenu = new PopupMenu();
  392. }
  393. PopupMenu popupMenu = tag.PopupMenu;
  394. BarButtonItem item = new BarButtonItem();
  395. item.ItemClick += (sender, e) =>
  396. {
  397. SaveFileDialog dialog = new SaveFileDialog();
  398. dialog.Filter = "csv|*.csv";
  399. if (dialog.ShowDialog() == DialogResult.OK)
  400. {
  401. var view = grid.MainView as GridView;
  402. view.ExportToCsv(dialog.FileName);
  403. }
  404. };
  405. item.ImageOptions.SvgImage = DxHelper.SvgHelper.CreateExportCsv();
  406. item.Caption = "导出(CSV)";
  407. tag.BarM.Items.Add(item);
  408. popupMenu.AddItem(item);
  409. popupMenu.Manager = tag.BarM;
  410. tag.PopupMenu = popupMenu;
  411. return grid;
  412. }
  413. public static GridControl UseExportXlsx(this GridControl grid)
  414. {
  415. GridTag tag = grid.Tag as GridTag;
  416. if (tag.BarM == null)
  417. {
  418. tag.BarM = new BarManager();
  419. tag.BarM.Form = grid;
  420. }
  421. if (tag.PopupMenu == null)
  422. {
  423. tag.PopupMenu = new PopupMenu();
  424. }
  425. PopupMenu popupMenu = tag.PopupMenu;
  426. BarButtonItem item = new BarButtonItem();
  427. item.ItemClick += (sender, e) =>
  428. {
  429. SaveFileDialog dialog = new SaveFileDialog();
  430. dialog.Filter = "Excel文件|*.xlsx";
  431. if (dialog.ShowDialog() == DialogResult.OK)
  432. {
  433. var view = grid.MainView as GridView;
  434. view.ExportToXlsx(dialog.FileName);
  435. }
  436. };
  437. item.ImageOptions.SvgImage = DxHelper.SvgHelper.CreateExportXlsx();
  438. item.Caption = "导出(Excel)";
  439. tag.BarM.Items.Add(item);
  440. popupMenu.AddItem(item);
  441. popupMenu.Manager = tag.BarM;
  442. tag.PopupMenu = popupMenu;
  443. return grid;
  444. }
  445. private static void View_KeyUp(object sender, KeyEventArgs e)
  446. {
  447. if (e.Control && e.Shift & e.KeyCode == Keys.C)
  448. {
  449. var view = sender as GridView;
  450. if (view.FocusedColumn == null) return;
  451. var val = view.GetFocusedRowCellDisplayText(view.FocusedColumn);
  452. if (string.IsNullOrWhiteSpace(val)) return;
  453. Clipboard.SetText(val);
  454. }
  455. }
  456. private static void View_CustomColumnDisplayText(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnDisplayTextEventArgs e)
  457. {
  458. if (e.Column.ColumnType == typeof(DateTime) || e.Column.ColumnType == typeof(DateTime?))
  459. {
  460. if (e.Value == null) return;
  461. if (e.Column.FieldName == "SigTime")
  462. e.DisplayText = Convert.ToDateTime(e.Value).ToString("yyyy-MM-dd HH:mm:ss.fff");
  463. else
  464. e.DisplayText = Convert.ToDateTime(e.Value).ToString("yyyy-MM-dd HH:mm:ss");
  465. }
  466. }
  467. public static GridControl ShowColumn(this GridControl grid, params string[] colField)
  468. {
  469. var view = grid.MainView as GridView;
  470. if (view.Columns.Count == 0) return grid;
  471. if (colField == null || colField.Length == 0) return grid;
  472. foreach (GridColumn item in view.Columns)
  473. {
  474. if (colField.Contains(item.FieldName))
  475. item.Visible = true;
  476. }
  477. return grid;
  478. }
  479. public static GridControl UseMultiSelect(this GridControl grid)
  480. {
  481. var view = grid.MainView as GridView;
  482. view.OptionsSelection.MultiSelect = true;
  483. view.OptionsSelection.MultiSelectMode = GridMultiSelectMode.RowSelect;
  484. return grid;
  485. }
  486. public static GridControl UseGroup(this GridControl grid)
  487. {
  488. var view = grid.MainView as GridView;
  489. view.OptionsView.GroupFooterShowMode = GroupFooterShowMode.Hidden;
  490. view.OptionsView.ShowGroupPanel = true;
  491. view.OptionsCustomization.AllowGroup = true;
  492. view.OptionsCustomization.AllowSort = true;
  493. return grid;
  494. }
  495. public static GridControl UseFooter(this GridControl grid, Action<object, DevExpress.XtraGrid.Views.Base.RowObjectCustomDrawEventArgs> act)
  496. {
  497. var view = grid.MainView as GridView;
  498. view.OptionsView.ShowFooter = true;
  499. view.CustomDrawFooter += (s, e) => act(s, e);
  500. return grid;
  501. }
  502. public static GridControl UseEdit(this GridControl grid)
  503. {
  504. var view = grid.MainView as GridView;
  505. view.OptionsBehavior.Editable = true;
  506. view.OptionsSelection.EnableAppearanceFocusedCell = true;
  507. foreach (GridColumn item in view.Columns)
  508. {
  509. item.OptionsColumn.AllowEdit = false;
  510. }
  511. return grid;
  512. }
  513. public static GridControl UseRowNumber(this GridControl grid)
  514. {
  515. var view = grid.MainView as GridView;
  516. view.OptionsView.ShowIndicator = true;
  517. view.CustomDrawRowIndicator += (s, e) =>
  518. {
  519. if (!e.Info.IsRowIndicator) return;
  520. if (e.RowHandle < 0) return;
  521. e.Handled = true;
  522. string txt = (e.RowHandle + 1).ToString();
  523. var txtSize = e.Graphics.MeasureString(txt, e.Appearance.Font);
  524. if (view.IndicatorWidth < txtSize.Width + 20)
  525. {
  526. view.IndicatorWidth++;
  527. }
  528. var loc = new PointF(e.Bounds.X + e.Bounds.Width / 2f - txtSize.Width / 2f + 2,
  529. e.Bounds.Y + e.Bounds.Height / 2f - txtSize.Height / 2f);
  530. e.Cache.FillRectangle(new SolidBrush(e.Appearance.BackColor), e.Bounds);
  531. e.Cache.DrawString(txt, e.Appearance.Font, new SolidBrush(e.Appearance.ForeColor), loc);
  532. };
  533. view.RowCountChanged += (sender, e) =>
  534. {
  535. if (view.RowCount == 0)
  536. view.IndicatorWidth = -1;
  537. else
  538. view.IndicatorWidth = view.RowCount.ToString().Length * 6 + 20;
  539. };
  540. return grid;
  541. }
  542. public static GridControl UseNullValueText(this GridControl grid, string nullText = "--")
  543. {
  544. var view = grid.MainView as GridView;
  545. view.CustomColumnDisplayText += (sender, e) =>
  546. {
  547. if (e.Value == null) e.DisplayText = nullText;
  548. };
  549. return grid;
  550. }
  551. public static GridControl SetDisplayText(this GridControl grid, string columnFieldName, Func<object, string> action)
  552. {
  553. var view = grid.MainView as GridView;
  554. view.CustomColumnDisplayText += (sender, e) =>
  555. {
  556. if (e.Column.FieldName != columnFieldName) return;
  557. if (e.Value == null || action == null) return;
  558. e.DisplayText = action(e.Value);
  559. };
  560. return grid;
  561. }
  562. public static GridControl HideColumn(this GridControl grid, params string[] colField)
  563. {
  564. var view = grid.MainView as GridView;
  565. if (colField == null || colField.Length == 0) return grid;
  566. foreach (GridColumn item in view.Columns)
  567. {
  568. if (colField.Contains(item.FieldName))
  569. item.Visible = false;
  570. }
  571. return grid;
  572. }
  573. /// <summary>
  574. /// GridControl添加单行元素选择后的右键菜单
  575. /// </summary>
  576. /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
  577. /// <param name="grid">GridControl控件</param>
  578. /// <param name="menuText">菜单标题</param>
  579. /// <param name="meunImage">菜单图标</param>
  580. /// <param name="action">菜单要执行的事件函数,参数为选中的单行元素</param>
  581. /// <param name="showCondition">菜单显示的条件</param>
  582. /// <returns></returns>
  583. public static GridControl AddRowMenu<T>(this GridControl grid, string menuText, SvgImage meunImage,
  584. Action<T> action, Func<T, bool> showCondition = null)
  585. {
  586. GridTag tag = grid.Tag as GridTag;
  587. var view = grid.MainView as GridView;
  588. if (tag.BarM == null)
  589. {
  590. tag.BarM = new BarManager();
  591. tag.BarM.Form = grid;
  592. }
  593. if (tag.PopupMenu == null)
  594. {
  595. tag.PopupMenu = new PopupMenu();
  596. }
  597. var popupMenu = tag.PopupMenu;
  598. BarButtonItem item = new BarButtonItem();
  599. tag.RowButtonsItems.Add(item);
  600. Func<bool> showConditionAll = () =>
  601. {
  602. if (!view.GetSelectedRows().Any()) return false;
  603. if (showCondition == null)
  604. return true;
  605. else
  606. return showCondition((T)view.GetFocusedRow());
  607. };
  608. item.Tag = showConditionAll;
  609. var handle = new ItemClickEventHandler((sender, e) =>
  610. {
  611. if (action != null)
  612. {
  613. if (view.GetFocusedRow() == null) return;
  614. item.Enabled = false;
  615. action.Invoke((T)view.GetFocusedRow());
  616. item.Enabled = true;
  617. }
  618. });
  619. item.Events().AddHandler(menuText, handle);
  620. item.ItemClick += handle;
  621. item.ImageOptions.SvgImage = meunImage;
  622. item.Caption = menuText;
  623. tag.BarM.Items.Add(item);
  624. popupMenu.AddItem(item);
  625. popupMenu.Manager = tag.BarM;
  626. tag.PopupMenu = popupMenu;
  627. return grid;
  628. }
  629. /// <summary>
  630. /// GridControl添加单行元素选择后的右键菜单
  631. /// </summary>
  632. /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
  633. /// <param name="grid">GridControl控件</param>
  634. /// <param name="menuText">菜单标题</param>
  635. /// <param name="meunImage">菜单图标</param>
  636. /// <param name="action">菜单要执行的异步事件函数,参数为选中的单行元素</param>
  637. /// <param name="showCondition">菜单显示的条件</param>
  638. /// <returns></returns>
  639. public static GridControl AddRowMenuAsync<T>(this GridControl grid, string menuText, SvgImage meunImage,
  640. Func<T, Task> action, Func<T, bool> showCondition = null)
  641. {
  642. GridTag tag = grid.Tag as GridTag;
  643. var view = grid.MainView as GridView;
  644. if (tag.BarM == null)
  645. {
  646. tag.BarM = new BarManager();
  647. tag.BarM.Form = grid;
  648. }
  649. if (tag.PopupMenu == null)
  650. {
  651. tag.PopupMenu = new PopupMenu();
  652. }
  653. var popupMenu = tag.PopupMenu;
  654. BarButtonItem item = new BarButtonItem();
  655. tag.RowButtonsItems.Add(item);
  656. Func<bool> showConditionAll = () =>
  657. {
  658. if (!view.GetSelectedRows().Any()) return false;
  659. if (showCondition == null)
  660. return true;
  661. else
  662. return showCondition((T)view.GetFocusedRow());
  663. };
  664. item.Tag = showConditionAll;
  665. var handle = new ItemClickEventHandler(async (sender, e) =>
  666. {
  667. if (action != null)
  668. {
  669. if (view.GetFocusedRow() == null) return;
  670. item.Enabled = false;
  671. await action.Invoke((T)view.GetFocusedRow());
  672. item.Enabled = true;
  673. }
  674. });
  675. item.Events().AddHandler(menuText, handle);
  676. item.ItemClick += handle;
  677. item.ImageOptions.SvgImage = meunImage;
  678. item.Caption = menuText;
  679. tag.BarM.Items.Add(item);
  680. popupMenu.AddItem(item);
  681. popupMenu.Manager = tag.BarM;
  682. tag.PopupMenu = popupMenu;
  683. return grid;
  684. }
  685. /// <summary>
  686. /// GridControl添加多行选择元素的右键菜单(自动启用UseMultiSelect)
  687. /// </summary>
  688. /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
  689. /// <param name="grid">GridControl控件</param>
  690. /// <param name="menuText">菜单标题</param>
  691. /// <param name="meunImage">菜单图标</param>
  692. /// <param name="action">菜单要执行的事件,参数为选中的一行或多行元素</param>
  693. /// <returns></returns>
  694. public static GridControl AddMultRowMenu<T>(this GridControl grid, string menuText, SvgImage meunImage,
  695. Action<List<T>> action)
  696. {
  697. grid.UseMultiSelect();
  698. GridTag tag = grid.Tag as GridTag;
  699. var view = grid.MainView as GridView;
  700. if (tag.BarM == null)
  701. {
  702. tag.BarM = new BarManager();
  703. tag.BarM.Form = grid;
  704. }
  705. if (tag.PopupMenu == null)
  706. {
  707. tag.PopupMenu = new PopupMenu();
  708. }
  709. var popupMenu = tag.PopupMenu;
  710. BarButtonItem item = new BarButtonItem();
  711. var handle = new ItemClickEventHandler((sender, e) =>
  712. {
  713. if (action != null)
  714. {
  715. var rows = view.GetSelectedRows();
  716. List<T> list = new List<T>();
  717. foreach (var row in rows)
  718. {
  719. if (row < 0) continue;
  720. list.Add((T)view.GetRow(row));
  721. }
  722. if (list.Any())
  723. action.Invoke(list);
  724. }
  725. });
  726. item.Events().AddHandler(menuText, handle);
  727. item.ItemClick += handle;
  728. item.ImageOptions.SvgImage = meunImage;
  729. item.Caption = menuText;
  730. Func<bool> showCondition = () => view.GetSelectedRows().Any();
  731. item.Tag = showCondition;
  732. tag.BarM.Items.Add(item);
  733. popupMenu.AddItem(item);
  734. popupMenu.Manager = tag.BarM;
  735. tag.PopupMenu = popupMenu;
  736. return grid;
  737. }
  738. /// <summary>
  739. /// GridControl添加多行选择元素的右键菜单(自动启用UseMultiSelect)
  740. /// </summary>
  741. /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
  742. /// <param name="grid">GridControl控件</param>
  743. /// <param name="menuText">菜单标题</param>
  744. /// <param name="meunImage">菜单图标</param>
  745. /// <param name="action">菜单要执行的异步事件函数,参数为选中的一行或多行元素</param>
  746. /// <returns></returns>
  747. public static GridControl AddMultRowMenuAsync<T>(this GridControl grid, string menuText, SvgImage meunImage,
  748. Func<List<T>, Task> action)
  749. {
  750. grid.UseMultiSelect();
  751. GridTag tag = grid.Tag as GridTag;
  752. var view = grid.MainView as GridView;
  753. if (tag.BarM == null)
  754. {
  755. tag.BarM = new BarManager();
  756. tag.BarM.Form = grid;
  757. }
  758. if (tag.PopupMenu == null)
  759. {
  760. tag.PopupMenu = new PopupMenu();
  761. }
  762. var popupMenu = tag.PopupMenu;
  763. BarButtonItem item = new BarButtonItem();
  764. var handle = new ItemClickEventHandler(async (sender, e) =>
  765. {
  766. if (action != null)
  767. {
  768. var rows = view.GetSelectedRows();
  769. List<T> list = new List<T>();
  770. foreach (var row in rows)
  771. {
  772. if (row < 0) continue;
  773. list.Add((T)view.GetRow(row));
  774. }
  775. if (list.Any())
  776. await action.Invoke(list);
  777. }
  778. });
  779. item.Events().AddHandler(menuText, handle);
  780. item.ItemClick += handle;
  781. item.ImageOptions.SvgImage = meunImage;
  782. item.Caption = menuText;
  783. Func<bool> showCondition = () => view.GetSelectedRows().Any();
  784. item.Tag = showCondition;
  785. tag.BarM.Items.Add(item);
  786. popupMenu.AddItem(item);
  787. popupMenu.Manager = tag.BarM;
  788. tag.PopupMenu = popupMenu;
  789. return grid;
  790. }
  791. /// <summary>
  792. /// GridControl添加内容区的右键菜单
  793. /// </summary>
  794. /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
  795. /// <param name="grid">GridControl控件</param>
  796. /// <param name="menuText">菜单标题</param>
  797. /// <param name="meunImage">菜单图标</param>
  798. /// <param name="action">菜单要执行的事件,参数为绑定的数据源</param>
  799. /// <param name="showWithNoneDataRow">内容区没有元素时是否显示此菜单,默认显示</param>
  800. /// <returns></returns>
  801. public static GridControl AddContentMenu<T>(this GridControl grid, string menuText, SvgImage meunImage,
  802. Action<List<T>> action, bool showWithNoneDataRow = true)
  803. {
  804. GridTag tag = grid.Tag as GridTag;
  805. var view = grid.MainView as GridView;
  806. if (tag.BarM == null)
  807. {
  808. tag.BarM = new BarManager();
  809. tag.BarM.Form = grid;
  810. }
  811. if (tag.PopupMenu == null)
  812. {
  813. tag.PopupMenu = new PopupMenu();
  814. }
  815. var popupMenu = tag.PopupMenu;
  816. BarButtonItem item = new BarButtonItem();
  817. var handle = new ItemClickEventHandler((sender, e) =>
  818. {
  819. if (action != null)
  820. {
  821. var ds = grid.DataSource as List<T>;
  822. if (!showWithNoneDataRow && (ds == null || ds.Count == 0)) return;
  823. item.Enabled = false;
  824. action.Invoke(ds);
  825. item.Enabled = true;
  826. }
  827. });
  828. item.Events().AddHandler(menuText, handle);
  829. item.ItemClick += handle;
  830. item.ImageOptions.SvgImage = meunImage;
  831. item.Caption = menuText;
  832. tag.BarM.Items.Add(item);
  833. popupMenu.AddItem(item);
  834. popupMenu.Manager = tag.BarM;
  835. tag.PopupMenu = popupMenu;
  836. return grid;
  837. }
  838. /// <summary>
  839. /// GridControl添加内容区的右键菜单
  840. /// </summary>
  841. /// <typeparam name="T">GridControl绑定数据源的泛型类型</typeparam>
  842. /// <param name="grid">GridControl控件</param>
  843. /// <param name="menuText">菜单标题</param>
  844. /// <param name="meunImage">菜单图标</param>
  845. /// <param name="action">菜单要执行的事件,参数为绑定的数据源</param>
  846. /// <param name="showWithNoneDataRow">内容区没有元素时是否显示此菜单,默认显示</param>
  847. /// <returns></returns>
  848. public static GridControl AddContentMenuAsync<T>(this GridControl grid, string menuText, SvgImage meunImage,
  849. Func<List<T>, Task> action, bool showWithNoneDataRow = true)
  850. {
  851. GridTag tag = grid.Tag as GridTag;
  852. var view = grid.MainView as GridView;
  853. if (tag.BarM == null)
  854. {
  855. tag.BarM = new BarManager();
  856. tag.BarM.Form = grid;
  857. }
  858. if (tag.PopupMenu == null)
  859. {
  860. tag.PopupMenu = new PopupMenu();
  861. }
  862. var popupMenu = tag.PopupMenu;
  863. BarButtonItem item = new BarButtonItem();
  864. var handle = new ItemClickEventHandler(async (sender, e) =>
  865. {
  866. if (action != null)
  867. {
  868. var ds = grid.DataSource as List<T>;
  869. if (!showWithNoneDataRow && (ds == null || ds.Count == 0)) return;
  870. item.Enabled = false;
  871. await action.Invoke(ds);
  872. item.Enabled = true;
  873. }
  874. });
  875. item.Events().AddHandler(menuText, handle);
  876. item.ItemClick += handle;
  877. item.ImageOptions.SvgImage = meunImage;
  878. item.Caption = menuText;
  879. tag.BarM.Items.Add(item);
  880. popupMenu.AddItem(item);
  881. popupMenu.Manager = tag.BarM;
  882. tag.PopupMenu = popupMenu;
  883. return grid;
  884. }
  885. private static void View_PopupMenuShowing(object sender, PopupMenuShowingEventArgs e)
  886. {
  887. if (e.Menu != null)
  888. {
  889. foreach (DXMenuItem item in e.Menu.Items)
  890. {
  891. if (!item.Enabled)
  892. {
  893. item.Visible = false;
  894. continue;
  895. }
  896. }
  897. }
  898. //if (e.HitInfo.HitTest == DevExpress.XtraGrid.Views.Grid.ViewInfo.GridHitTest.EmptyRow)
  899. //{
  900. // return;
  901. //}
  902. var view = sender as GridView;
  903. var grid = view.GridControl;
  904. var p = grid.PointToScreen(e.Point);
  905. var tag = grid.Tag as GridTag;
  906. if (tag?.PopupMenu != null)
  907. {
  908. foreach (BarButtonItemLink item in tag?.PopupMenu?.ItemLinks)
  909. {
  910. var buttonItem = item.Item;
  911. if (buttonItem.Tag != null && buttonItem.Tag is Func<bool> showCondition)
  912. {
  913. if (showCondition())
  914. buttonItem.Visibility = BarItemVisibility.Always;
  915. else
  916. buttonItem.Visibility = BarItemVisibility.Never;
  917. }
  918. }
  919. tag?.PopupMenu?.ShowPopup(p);
  920. }
  921. }
  922. public static GridControl DrawGridColumnHeaderCheckBox(this GridControl grid)
  923. {
  924. //View的 Editable要为true
  925. var view = grid.MainView as GridView;
  926. view.OptionsBehavior.Editable = true;
  927. view.OptionsSelection.MultiSelect = true;
  928. view.OptionsSelection.MultiSelectMode = GridMultiSelectMode.CheckBoxRowSelect;
  929. return grid;
  930. }
  931. }