一.关于ListEditor
ListEditor是ListView的可视化体现。ListEditor拥有一个Control,该Control的作用是显示ListView的对象集合。ListEditor管理该Control,负责Control的创建,数据绑定和管理Control与ListView之间的交互。
从现有View获取ListEditor及其Control:
- ListEditor editor=((ListView)View).Editor;
- //若该ListEditor的control是GridControl,使用ListEditor.Control属性获取该Control
- 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中声明该接口。
- using System.Drawing;
- interface IPictureItem {
- Image Image { get; }
- string Text { get; }
- string ID { get; }
- }
using System.Drawing;
interface IPictureItem {
Image Image { get; }
string Text { get; }
string ID { get; }
}
然后在Solution.Module.Win中实现自定义的ListEditor类
- /*Typical implementation of the ListEditor class' descendants comprises the following steps:
- 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:
- - OnProcessSelectedItem
- - OnSelectionChanged
- - OnFocusedObjectChanging
- - OnFocusedObjectChanged
- - OnNewObjectAdding
- - OnNewObjectCanceled
- - OnNewObjectCreated
- 2.Override the AssignDataSourceToControl method. Assign the List Editor's data source to its control.
- 3.Override the Refresh method. Refresh data in the List Editor's control.
- 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.
- 5.Override the SelectionType property. Return the selection type supported by the List Editor's control.
- 6.Override the GetSelectedObjects method. Return a list of the selected objects.
- 7.Override the FocusedObject method. Get and set the control's focused object.
- 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.
- 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.
- 10.Mark the custom List Editor with the ListEditorAttribute.
- */
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- using DevExpress.ExpressApp.Editors;
- using System.Windows.Forms;
- using System.ComponentModel;
- using DevExpress.ExpressApp.Utils;
- using DevExpress.ExpressApp;
- using DevExpress.ExpressApp.Model;
- using System.Collections;
- using DevExpress.ExpressApp.Templates;
- using DevExpress.ExpressApp.Win.Controls;
- using DevExpress.Utils.Menu;
- using System.Drawing;
- using DevExpress.ExpressApp.SystemModule;
- using ListEditorSolution.Module;
- namespace ListEditorSolution.Module.Win
- {
- /*自定义WinCustomListEditor需要继承ListEditor;若要为其实现上下文菜单,则需要实现
- IDXPopupMenuHolder接口,该接口暴露了如下成员,需要重写它们:
- CanShowPopupMenu
- SetMenuManager
- PopupSite
- */
- //该ListEditor属性表示为IPictureItem类型使用WinCustomListEditor
- [ListEditor(typeof(IPictureItem))]
- public class WinCustomListEditor : ListEditor, IDXPopupMenuHolder
- {
- //上下文菜单
- private ActionsDXPopupMenu popupMenu;
- //ListView is a Control.声明WinCustomListEditor的Control
- private System.Windows.Forms.ListView control;
- private System.Windows.Forms.ImageList images;
- //ListEditor的数据集合
- private IList controlDataSource;
- public WinCustomListEditor(IModelListView info) : base(info)
- {
- //初始化上下文菜单
- popupMenu = new ActionsDXPopupMenu();
- }
- //实例化WinCustomListEditor的control,并配置该control
- protected override object CreateControlsCore()
- {
- control = new System.Windows.Forms.ListView();
- images = new System.Windows.Forms.ImageList();
- images.ImageSize = new System.Drawing.Size(104, 150);
- images.ColorDepth = ColorDepth.Depth32Bit;
- control.LargeImageList = images;
- control.HideSelection = false;
- //订阅选中,焦点等事件
- /*只要 ListViewItem 的 Selected 属性发生改变,SelectedIndices 集合就会更改。
- 属性更改可以编程方式发生,也可以在用户选择项或取消选择项时发生。
- 当用户选择某项(但没有按 Ctrl 选择多项)时,该控件首先取消选择以前选择的项。
- 在这种情况下,此事件会发生两次,一次是针对以前选择的每一项,一次是针对新选择的项。*/
- control.SelectedIndexChanged += new EventHandler(control_SelectedIndexChanged);
- //项状态无论是从选定变为非选定,还是从非选定变为选定,均发生 ItemSelectionChanged 事件
- control.ItemSelectionChanged +=
- new System.Windows.Forms.ListViewItemSelectionChangedEventHandler(
- control_ItemSelectionChanged);
- //订阅鼠标双击,按下Enter键事件
- control.MouseDoubleClick += new MouseEventHandler(control_MouseDoubleClick);
- control.KeyDown += new System.Windows.Forms.KeyEventHandler(control_KeyDown);
- Refresh();
- return control;
- }
- //绑定ListEditor的数据源到它的control,当数据源是IBindingList,订阅数据更改事件
- protected override void AssignDataSourceToControl(object oDataSource)
- {
- IList dataSource = (IList)oDataSource;
- if (controlDataSource != dataSource)
- {
- IBindingList oldBindable = controlDataSource as IBindingList;
- if (oldBindable != null)
- {
- oldBindable.ListChanged -= new ListChangedEventHandler(dataSource_ListChanged);
- }
- controlDataSource = dataSource;
- //若数据集合实现了IBindingList,则订阅ListChanged事件
- IBindingList bindable = controlDataSource as IBindingList;
- if (bindable != null)
- {
- bindable.ListChanged += new ListChangedEventHandler(dataSource_ListChanged);
- }
- Refresh();
- }
- }
- void dataSource_ListChanged(object sender, ListChangedEventArgs e)
- {
- Refresh();
- }
- public override void Refresh()
- {
- if (control == null)
- return;
- //保存FocusedObject
- object focused = FocusedObject;
- control.SelectedItems.Clear();
- try
- {
- /*将多个项添加到 ListView 的首选方法是使用 ListView.ListViewItemCollection(通过
- ListView 的 Items 属性访问)的 AddRange 方法。这使您得以在一个操作中就可将一组项添
- 加到列表中。然而,如果希望使用 ListView.ListViewItemCollection 类的 Add 方法以每
- 次一个的方式添加项,则可以使用 BeginUpdate 方法防止控件在每次添加项时重新绘制 ListView。
- 在完成将项添加到控件的任务后,请调用 EndUpdate 方法以使 ListView 能够重新绘制。这种添加
- 项的方法可以防止将大量项添加到控件时发生闪烁的 ListView 绘制*/
- control.BeginUpdate();
- images.Images.Clear();
- control.Items.Clear();
- //得到IList类型的数据集合
- if (ListHelper.GetList(controlDataSource) != null)
- {
- //Module.Win.Image下必须存在NoImage 图片作为默认图片
- images.Images.Add(ImageLoader.Instance.GetImageInfo("NoImage").Image);
- foreach (IPictureItem item in ListHelper.GetList(controlDataSource))
- {
- int imageIndex = 0;
- if (item.Image != null)
- {
- images.Images.Add(item.Image);
- imageIndex = images.Images.Count - 1;
- }
- //创建并初始化一个ListViewItem
- System.Windows.Forms.ListViewItem lItem =
- new System.Windows.Forms.ListViewItem(item.Text, imageIndex);
- //附加图片,ListViewItem利用构造函数参数的imageIndex索引该图片对象
- lItem.Tag = item;
- //将该ListViewItem添加到ListView中
- control.Items.Add(lItem);
- }
- }
- }
- finally
- {
- control.EndUpdate();
- }
- //恢复FocusedObject
- FocusedObject = focused;
- if (FocusedObject == null && control.Items.Count > 1)
- {
- FocusedObject = control.Items[0].Tag;
- }
- }
- //接触数据绑定,销毁上下文菜单
- public override void Dispose()
- {
- controlDataSource = null;
- if (popupMenu != null)
- {
- popupMenu.Dispose();
- popupMenu = null;
- }
- base.Dispose();
- }
- void control_ItemSelectionChanged(object sender,System.Windows.Forms.ListViewItemSelectionChangedEventArgs e)
- {
- OnSelectionChanged();
- }
- void control_SelectedIndexChanged(object sender, EventArgs e)
- {
- OnSelectionChanged();
- OnFocusedObjectChanged();
- }
- public override SelectionType SelectionType
- {
- get { return SelectionType.Full; }
- }
- public override IList GetSelectedObjects()
- {
- if (control == null) return new object[0] { };
- object[] result = new object[control.SelectedItems.Count];
- for (int i = 0; i < control.SelectedItems.Count; i++)
- {
- result[i] = control.SelectedItems[i].Tag;
- }
- return result;
- }
- void control_KeyDown(object sender, System.Windows.Forms.KeyEventArgs e)
- {
- if (e.KeyCode == Keys.Enter)
- OnProcessSelectedItem();
- }
- void control_MouseDoubleClick(object sender, MouseEventArgs e)
- {
- if (e.Button == MouseButtons.Left)
- {
- OnProcessSelectedItem();
- }
- }
- //根据已有的IPictureItem定位control中的ListViewItem
- private System.Windows.Forms.ListViewItem FindByTag(object tag)
- {
- IPictureItem itemToSearch = (IPictureItem)tag;
- if (control != null && itemToSearch != null)
- {
- foreach (System.Windows.Forms.ListViewItem item in control.Items)
- {
- if (((IPictureItem)item.Tag).ID == itemToSearch.ID)
- return item;
- }
- }
- return null;
- }
- public override object FocusedObject
- {
- get {
- return (control != null) && (control.FocusedItem != null) ?
- control.FocusedItem.Tag : null;
- }
- set
- {
- System.Windows.Forms.ListViewItem item = FindByTag(value);
- if (item != null)
- {
- control.SelectedItems.Clear();
- item.Focused = true;
- item.Selected = true;
- }
- }
- }
- public override IContextMenuTemplate ContextMenuTemplate
- {
- get { return popupMenu; }
- }
- public bool CanShowPopupMenu(System.Drawing.Point position)
- {
- System.Drawing.Point clientPosition = control.PointToClient(position);
- return clientPosition != Point.Empty;
- }
- public void SetMenuManager(IDXMenuManager manager) { }
- //返回右键菜单所属的control
- public Control PopupSite
- {
- get { return control; }
- }
- public override void SaveModel() { }
- }
- }
- 使用该ListEditor:
- [DefaultClassOptions]
- public class Persons : BaseObject , IPictureItem
- {
- public Persons(Session session)
- : base(session)
- {
- // This constructor is used when an object is loaded from a persistent storage.
- // Do not place any code here or place it only when the IsLoading property is false:
- // if (!IsLoading){
- // It is now OK to place your initialization code here.
- // }
- // or as an alternative, move your initialization code into the AfterConstruction method.
- }
- public override void AfterConstruction()
- {
- base.AfterConstruction();
- // Place here your initialization code.
- }
- public string Title
- {
- get { return GetPropertyValue<string>("Title"); }
- set { SetPropertyValue<string>("Title", value); }
- }
- [Size(SizeAttribute.Unlimited), ValueConverter(typeof(ImageValueConverter))]
- public Image Cover
- {
- get { return GetPropertyValue<Image>("Cover"); }
- set { SetPropertyValue<Image>("Cover", value); }
- }
- public String Director
- {
- get { return GetPropertyValue<String>("Director"); }
- set { SetPropertyValue<String>("Director", value); }
- }
- #region IPictureItem Members
- //这几个字段从IPictureItem继承而来,不是BaseObject的成员,不会在数据库生成字段
- Image IPictureItem.Image
- {
- get { return Cover; }
- }
- string IPictureItem.Text
- {
- get { return String.Format("{0} by {1}", Title, Director); }
- }
- string IPictureItem.ID
- {
- get { return Oid.ToString(); }
- }
- #endregion
- }