自定义ListEditor

一.关于ListEditor

ListEditor是ListView的可视化体现。ListEditor拥有一个Control,该Control的作用是显示ListView的对象集合。ListEditor管理该Control,负责Control的创建,数据绑定和管理Control与ListView之间的交互。

从现有View获取ListEditor及其Control:

  1. ListEditor editor=((ListView)View).Editor;
  2. //若该ListEditor的control是GridControl,使用ListEditor.Control属性获取该Control
  3. GridControl gc=(GridControl)editor.Control;
      ListEditor     editor=((ListView)View).Editor;
      //若该ListEditor的control是GridControl,使用ListEditor.Control属性获取该Control
     GridControl gc=(GridControl)editor.Control;

若要实现自定义的ListEditor,必须用ListEditorAttribute特性标记该自定义的类。

二.自定义ListEditor(该例来自于http://documentation.devexpress.com/#Xaf/CustomDocument2659 )

我们准备为一个图片类型实现自定义ListEditor,在Solution.Module中声明该接口。

  1. using System.Drawing;
  2. interface IPictureItem {
  3. Image Image { get; }
  4. string Text { get; }
  5. string ID { get; }
  6. }
using System.Drawing;
interface IPictureItem {
Image Image { get; }
string Text { get; }
string ID { get; }
}

然后在Solution.Module.Win中实现自定义的ListEditor类

  1. /*Typical implementation of the ListEditor class' descendants comprises the following steps:
  2. 1.Override the CreateControlsCore method. Create and configure an instance of the control that will represent a List View in a UI. Handle the control's events to call the following methods:
  3. - OnProcessSelectedItem
  4. - OnSelectionChanged
  5. - OnFocusedObjectChanging
  6. - OnFocusedObjectChanged
  7. - OnNewObjectAdding
  8. - OnNewObjectCanceled
  9. - OnNewObjectCreated
  10. 2.Override the AssignDataSourceToControl method. Assign the List Editor's data source to its control.
  11. 3.Override the Refresh method. Refresh data in the List Editor's control.
  12. 4.Override the RequiredProperties property. Return business class' property names that are used by the List Editor when displaying objects. These properties are treated as displayable if a List View's data source is derived from the XPBaseCollection.
  13. 5.Override the SelectionType property. Return the selection type supported by the List Editor's control.
  14. 6.Override the GetSelectedObjects method. Return a list of the selected objects.
  15. 7.Override the FocusedObject method. Get and set the control's focused object.
  16. 8.If the custom List Editor does not support server mode (CollectionSourceBase.IsServerMode), override the IsServerModeSupported property and set it to false. It is also recommended that you implement a custom generator updater to disable server mode for List Views visualized by the custom List Editor. For details, see the IsServerModeSupported property description.
  17. 9.Modify the constructor to instantiate the control that will represent the List Editor's pop-up menu. This control must implement the IDXPopupMenuHolder interface to support XAF architecture. Override the ContextMenuTemplate property to return the created instance of the control.
  18. 10.Mark the custom List Editor with the ListEditorAttribute.
  19. */
  20. using System;
  21. using System.Collections.Generic;
  22. using System.Linq;
  23. using System.Text;
  24. using DevExpress.ExpressApp.Editors;
  25. using System.Windows.Forms;
  26. using System.ComponentModel;
  27. using DevExpress.ExpressApp.Utils;
  28. using DevExpress.ExpressApp;
  29. using DevExpress.ExpressApp.Model;
  30. using System.Collections;
  31. using DevExpress.ExpressApp.Templates;
  32. using DevExpress.ExpressApp.Win.Controls;
  33. using DevExpress.Utils.Menu;
  34. using System.Drawing;
  35. using DevExpress.ExpressApp.SystemModule;
  36. using ListEditorSolution.Module;
  37. namespace ListEditorSolution.Module.Win
  38. {
  39. /*自定义WinCustomListEditor需要继承ListEditor;若要为其实现上下文菜单,则需要实现
  40. IDXPopupMenuHolder接口,该接口暴露了如下成员,需要重写它们:
  41. CanShowPopupMenu
  42. SetMenuManager
  43. PopupSite
  44. */
  45. //该ListEditor属性表示为IPictureItem类型使用WinCustomListEditor
  46. [ListEditor(typeof(IPictureItem))]
  47. public class WinCustomListEditor : ListEditor, IDXPopupMenuHolder
  48. {
  49. //上下文菜单
  50. private ActionsDXPopupMenu popupMenu;
  51. //ListView is a Control.声明WinCustomListEditor的Control
  52. private System.Windows.Forms.ListView control;
  53. private System.Windows.Forms.ImageList images;
  54. //ListEditor的数据集合
  55. private IList controlDataSource;
  56. public WinCustomListEditor(IModelListView info) : base(info)
  57. {
  58. //初始化上下文菜单
  59. popupMenu = new ActionsDXPopupMenu();
  60. }
  61. //实例化WinCustomListEditor的control,并配置该control
  62. protected override object CreateControlsCore()
  63. {
  64. control = new System.Windows.Forms.ListView();
  65. images = new System.Windows.Forms.ImageList();
  66. images.ImageSize = new System.Drawing.Size(104, 150);
  67. images.ColorDepth = ColorDepth.Depth32Bit;
  68. control.LargeImageList = images;
  69. control.HideSelection = false;
  70. //订阅选中,焦点等事件
  71. /*只要 ListViewItem 的 Selected 属性发生改变,SelectedIndices 集合就会更改。
  72. 属性更改可以编程方式发生,也可以在用户选择项或取消选择项时发生。
  73. 当用户选择某项(但没有按 Ctrl 选择多项)时,该控件首先取消选择以前选择的项。
  74. 在这种情况下,此事件会发生两次,一次是针对以前选择的每一项,一次是针对新选择的项。*/
  75. control.SelectedIndexChanged += new EventHandler(control_SelectedIndexChanged);
  76. //项状态无论是从选定变为非选定,还是从非选定变为选定,均发生 ItemSelectionChanged 事件
  77. control.ItemSelectionChanged +=
  78. new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(
  79. control_ItemSelectionChanged);
  80. //订阅鼠标双击,按下Enter键事件
  81. control.MouseDoubleClick += new MouseEventHandler(control_MouseDoubleClick);
  82. control.KeyDown += new System.Windows.Forms.KeyEventHandler(control_KeyDown);
  83. Refresh();
  84. return control;
  85. }
  86. //绑定ListEditor的数据源到它的control,当数据源是IBindingList,订阅数据更改事件
  87. protected override void AssignDataSourceToControl(object oDataSource)
  88. {
  89. IList dataSource = (IList)oDataSource;
  90. if (controlDataSource != dataSource)
  91. {
  92. IBindingList oldBindable = controlDataSource as IBindingList;
  93. if (oldBindable != null)
  94. {
  95. oldBindable.ListChanged -= new ListChangedEventHandler(dataSource_ListChanged);
  96. }
  97. controlDataSource = dataSource;
  98. //若数据集合实现了IBindingList,则订阅ListChanged事件
  99. IBindingList bindable = controlDataSource as IBindingList;
  100. if (bindable != null)
  101. {
  102. bindable.ListChanged += new ListChangedEventHandler(dataSource_ListChanged);
  103. }
  104. Refresh();
  105. }
  106. }
  107. void dataSource_ListChanged(object sender, ListChangedEventArgs e)
  108. {
  109. Refresh();
  110. }
  111. public override void Refresh()
  112. {
  113. if (control == null)
  114. return;
  115. //保存FocusedObject
  116. object focused = FocusedObject;
  117. control.SelectedItems.Clear();
  118. try
  119. {
  120. /*将多个项添加到 ListView 的首选方法是使用 ListView.ListViewItemCollection(通过
  121. ListView 的 Items 属性访问)的 AddRange 方法。这使您得以在一个操作中就可将一组项添
  122. 加到列表中。然而,如果希望使用 ListView.ListViewItemCollection 类的 Add 方法以每
  123. 次一个的方式添加项,则可以使用 BeginUpdate 方法防止控件在每次添加项时重新绘制 ListView。
  124. 在完成将项添加到控件的任务后,请调用 EndUpdate 方法以使 ListView 能够重新绘制。这种添加
  125. 项的方法可以防止将大量项添加到控件时发生闪烁的 ListView 绘制*/
  126. control.BeginUpdate();
  127. images.Images.Clear();
  128. control.Items.Clear();
  129. //得到IList类型的数据集合
  130. if (ListHelper.GetList(controlDataSource) != null)
  131. {
  132. //Module.Win.Image下必须存在NoImage 图片作为默认图片
  133. images.Images.Add(ImageLoader.Instance.GetImageInfo("NoImage").Image);
  134. foreach (IPictureItem item in ListHelper.GetList(controlDataSource))
  135. {
  136. int imageIndex = 0;
  137. if (item.Image != null)
  138. {
  139. images.Images.Add(item.Image);
  140. imageIndex = images.Images.Count - 1;
  141. }
  142. //创建并初始化一个ListViewItem
  143. System.Windows.Forms.ListViewItem lItem =
  144. new System.Windows.Forms.ListViewItem(item.Text, imageIndex);
  145. //附加图片,ListViewItem利用构造函数参数的imageIndex索引该图片对象
  146. lItem.Tag = item;
  147. //将该ListViewItem添加到ListView中
  148. control.Items.Add(lItem);
  149. }
  150. }
  151. }
  152. finally
  153. {
  154. control.EndUpdate();
  155. }
  156. //恢复FocusedObject
  157. FocusedObject = focused;
  158. if (FocusedObject == null && control.Items.Count > 1)
  159. {
  160. FocusedObject = control.Items[0].Tag;
  161. }
  162. }
  163. //接触数据绑定,销毁上下文菜单
  164. public override void Dispose()
  165. {
  166. controlDataSource = null;
  167. if (popupMenu != null)
  168. {
  169. popupMenu.Dispose();
  170. popupMenu = null;
  171. }
  172. base.Dispose();
  173. }
  174. void control_ItemSelectionChanged(object sender,System.Windows.Forms.ListViewItemSelectionChangedEventArgs e)
  175. {
  176. OnSelectionChanged();
  177. }
  178. void control_SelectedIndexChanged(object sender, EventArgs e)
  179. {
  180. OnSelectionChanged();
  181. OnFocusedObjectChanged();
  182. }
  183. public override SelectionType SelectionType
  184. {
  185. get { return SelectionType.Full; }
  186. }
  187. public override IList GetSelectedObjects()
  188. {
  189. if (control == null) return new object[0] { };
  190. object[] result = new object[control.SelectedItems.Count];
  191. for (int i = 0; i < control.SelectedItems.Count; i++)
  192. {
  193. result[i] = control.SelectedItems[i].Tag;
  194. }
  195. return result;
  196. }
  197. void control_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
  198. {
  199. if (e.KeyCode == Keys.Enter)
  200. OnProcessSelectedItem();
  201. }
  202. void control_MouseDoubleClick(object sender, MouseEventArgs e)
  203. {
  204. if (e.Button == MouseButtons.Left)
  205. {
  206. OnProcessSelectedItem();
  207. }
  208. }
  209. //根据已有的IPictureItem定位control中的ListViewItem
  210. private System.Windows.Forms.ListViewItem FindByTag(object tag)
  211. {
  212. IPictureItem itemToSearch = (IPictureItem)tag;
  213. if (control != null && itemToSearch != null)
  214. {
  215. foreach (System.Windows.Forms.ListViewItem item in control.Items)
  216. {
  217. if (((IPictureItem)item.Tag).ID == itemToSearch.ID)
  218. return item;
  219. }
  220. }
  221. return null;
  222. }
  223. public override object FocusedObject
  224. {
  225. get {
  226. return (control != null) && (control.FocusedItem != null) ?
  227. control.FocusedItem.Tag : null;
  228. }
  229. set
  230. {
  231. System.Windows.Forms.ListViewItem item = FindByTag(value);
  232. if (item != null)
  233. {
  234. control.SelectedItems.Clear();
  235. item.Focused = true;
  236. item.Selected = true;
  237. }
  238. }
  239. }
  240. public override IContextMenuTemplate ContextMenuTemplate
  241. {
  242. get { return popupMenu; }
  243. }
  244. public bool CanShowPopupMenu(System.Drawing.Point position)
  245. {
  246. System.Drawing.Point clientPosition = control.PointToClient(position);
  247. return clientPosition != Point.Empty;
  248. }
  249. public void SetMenuManager(IDXMenuManager manager) { }
  250. //返回右键菜单所属的control
  251. public Control PopupSite
  252. {
  253. get { return control; }
  254. }
  255. public override void SaveModel() { }
  256. }
  257. }
  258. 使用该ListEditor:
  259. [DefaultClassOptions]
  260. public class Persons : BaseObject , IPictureItem
  261. {
  262. public Persons(Session session)
  263. : base(session)
  264. {
  265. // This constructor is used when an object is loaded from a persistent storage.
  266. // Do not place any code here or place it only when the IsLoading property is false:
  267. // if (!IsLoading){
  268. // It is now OK to place your initialization code here.
  269. // }
  270. // or as an alternative, move your initialization code into the AfterConstruction method.
  271. }
  272. public override void AfterConstruction()
  273. {
  274. base.AfterConstruction();
  275. // Place here your initialization code.
  276. }
  277. public string Title
  278. {
  279. get { return GetPropertyValue<string>("Title"); }
  280. set { SetPropertyValue<string>("Title", value); }
  281. }
  282. [Size(SizeAttribute.Unlimited), ValueConverter(typeof(ImageValueConverter))]
  283. public Image Cover
  284. {
  285. get { return GetPropertyValue<Image>("Cover"); }
  286. set { SetPropertyValue<Image>("Cover", value); }
  287. }
  288. public String Director
  289. {
  290. get { return GetPropertyValue<String>("Director"); }
  291. set { SetPropertyValue<String>("Director", value); }
  292. }
  293. #region IPictureItem Members
  294. //这几个字段从IPictureItem继承而来,不是BaseObject的成员,不会在数据库生成字段
  295. Image IPictureItem.Image
  296. {
  297. get { return Cover; }
  298. }
  299. string IPictureItem.Text
  300. {
  301. get { return String.Format("{0} by {1}", Title, Director); }
  302. }
  303. string IPictureItem.ID
  304. {
  305. get { return Oid.ToString(); }
  306. }
  307. #endregion
  308. }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值