Here is a Win/Web solution.
I have implemented a Web version of enumeration filtering. So the final solution has:
- filtering function of enumerable types
- win & web property editors that cooperate with DataSourceProperty and/or DataSourceCriteria attributes
- they work with nullable enum types
The solution (targetted to .NET Framework 4.0 ):
Example of use:
[C#]Open in popup window
[DefaultClassOptions]
public class BOWithAnEnum : BaseObject
{
private StatusColor? _status;
private bool _someSwitch;
public BOWithAnEnum(Session session) : base(session) { }
[DataSourceProperty("InstanceStatusDataSource")]
public StatusColor? Status {
get { return _status; }
set { SetPropertyValue("Status", ref _status, value); }
}
[ImmediatePostData]
public bool SomeSwitch {
get { return _someSwitch; }
set {
SetPropertyValue("SomeSwitch", ref _someSwitch, value);
OnChanged("InstanceStatusDataSource");
}
}
[Browsable(false)]
public static IList<StatusColor?> StaticStatusDataSource {
get {
return new StatusColor?[] {
StatusColor.Red,
StatusColor.Green };
}
}
[Browsable(false)]
public IList<StatusColor?> InstanceStatusDataSource {
get {
return SomeSwitch ?
new StatusColor?[] {
StatusColor.Red,
StatusColor.Green } :
new StatusColor?[] {
StatusColor.White,
StatusColor.Blue };
}
}
}
Helper class (add it to your platform-independent module, e.g., Application.Module):
[C#]Open in popup window
using System;
using System.Collections.Generic;
using System.ComponentModel;
using DevExpress.Data.Filtering;
using DevExpress.Persistent.Base;
namespace EnumEditSample.Module.Infrastructure {
public class EnumCriteriaParser : CriteriaProcessorBase {
private Dictionary<string, OperandValue> _values = new Dictionary<string, OperandValue>();
private static void UnsupportedCriteria() {
throw new InvalidEnumArgumentException("Unsupported criteria.");
}
private void UpdatePropertyName(CriteriaOperator operand) {
var operandProperty = operand as OperandProperty;
if ((ReferenceEquals(operandProperty, null)) ||
(!operandProperty.PropertyName.Equals(PropertyName)))
UnsupportedCriteria();
operandProperty.PropertyName = "Value";
}
private void ToValue(IList<CriteriaOperator> operands) {
CriteriaOperator operandValue;
for (int i = 0; i < operands.Count; i++)
if (ToValue(operands[i], out operandValue))
operands[i] = operandValue;
}
private bool ToValue(CriteriaOperator operand, out CriteriaOperator operandValue) {
operandValue = null;
string valueName;
if (operand is OperandProperty)
valueName = ((OperandProperty)operand).PropertyName;
else if (operand is OperandValue && ((OperandValue)operand).Value is string)
valueName = (string)((OperandValue)operand).Value;
else
return false;
operandValue = _values[valueName];
return true;
}
public EnumCriteriaParser(string propertyName, Type enumType) {
PropertyName = propertyName;
if (enumType.IsGenericType) {
var types = enumType.GetGenericArguments();
if (types.Length == 1 && typeof(Nullable<>).MakeGenericType(types[0]).Equals(enumType))
enumType = types[0];
}
EnumType = enumType;
foreach (object value in Enum.GetValues(enumType))
_values.Add(value.ToString(), new OperandValue(value));
}
public object Visit(InOperator theOperator) {
UpdatePropertyName(theOperator.LeftOperand);
ToValue(theOperator.Operands);
return theOperator;
}
protected override void Process(InOperator theOperator) {
UpdatePropertyName(theOperator.LeftOperand);
ToValue(theOperator.Operands);
base.Process(theOperator);
}
protected override void Process(UnaryOperator theOperator) {
switch (theOperator.OperatorType) {
case UnaryOperatorType.IsNull: UpdatePropertyName(theOperator.Operand); break;
case UnaryOperatorType.Not: theOperator.Operand.Accept(this); break;
}
base.Process(theOperator);
}
protected override void Process(BinaryOperator theOperator) {
UpdatePropertyName(theOperator.LeftOperand);
CriteriaOperator operandValue;
if (ToValue(theOperator.RightOperand, out operandValue))
theOperator.RightOperand = operandValue;
else
theOperator.RightOperand.Accept(this);
base.Process(theOperator);
}
protected override void Process(BetweenOperator theOperator) {
UpdatePropertyName(theOperator.TestExpression);
CriteriaOperator operandValue;
if (ToValue((OperandProperty)theOperator.BeginExpression, out operandValue))
theOperator.BeginExpression = operandValue;
else
theOperator.BeginExpression.Accept(this);
if (ToValue((OperandProperty)theOperator.EndExpression, out operandValue))
theOperator.EndExpression = operandValue;
else
theOperator.EndExpression.Accept(this);
base.Process(theOperator);
}
public string PropertyName { get; private set; }
public Type EnumType { get; private set; }
}
}
WIN property editor for enum filtering (add it to your WinForms module, e.g., Application.Module.Win):
[C#]Open in popup window
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;
using DevExpress.Data.Filtering;
using DevExpress.Data.Filtering.Helpers;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.DC;
using DevExpress.ExpressApp.Editors;
using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.Win.Core;
using DevExpress.ExpressApp.Win.Editors;
using DevExpress.XtraEditors;
using DevExpress.XtraEditors.Controls;
using DevExpress.XtraEditors.Drawing;
using DevExpress.XtraEditors.Popup;
using DevExpress.XtraEditors.Registrator;
using DevExpress.XtraEditors.Repository;
using DevExpress.XtraEditors.ViewInfo;
using EnumEditSample.Module.Infrastructure;
namespace Kraan.ExpressApp.Win.Framework.Editors.Xaf {
[PropertyEditor(typeof(Enum), EditorAliases.EnumPropertyEditor)]
public class FilterableEnumPropertyEditor : DXPropertyEditor, IComplexViewItem {
private void UpdateControlWithCurrentObject() {
var control = Control as IGridInplaceEdit;
if (control != null)
control.GridEditingObject = CurrentObject;
}
protected override object CreateControlCore() {
return new XafEnumEdit();
}
protected override RepositoryItem CreateRepositoryItem() {
return new RepositoryItemXafEnumEdit();
}
protected override void SetupRepositoryItem(RepositoryItem item) {
base.SetupRepositoryItem(item);
var enumEditRepositoryItem = item as RepositoryItemXafEnumEdit;
enumEditRepositoryItem.Setup(Application, ObjectSpace, Model);
UpdateControlWithCurrentObject();
}
protected override void OnCurrentObjectChanged() {
base.OnCurrentObjectChanged();
UpdateControlWithCurrentObject();
}
public FilterableEnumPropertyEditor(Type objectType, IModelMemberViewItem model)
: base(objectType, model) {
ImmediatePostData = model.ImmediatePostData;
}
public new ComboBoxEdit Control {
get { return (ComboBoxEdit)base.Control; }
}
public void Setup(IObjectSpace objectSpace, XafApplication application) {
Application = application;
ObjectSpace = objectSpace;
}
public XafApplication Application { get; private set; }
public IObjectSpace ObjectSpace { get; private set; }
}
[System.ComponentModel.DesignerCategory("")]
[System.ComponentModel.ToolboxItem(false)]
public class RepositoryItemXafEnumEdit : RepositoryItemImageComboBox {
private XafApplication _application;
private IObjectSpace _objectSpace;
private IModelMemberViewItem _model;
private IMemberInfo _propertyMemberInfo;
private IMemberInfo _dataSourceMemberInfo;
private ITypeInfo GetObjectTypeInfo(IModelMemberViewItem model) {
var objectView = model.ParentView as IModelObjectView;
return objectView != null ? objectView.ModelClass.TypeInfo : null;
}
internal const string EditorName = "XafEnumEdit";
internal static void Register() {
if (!EditorRegistrationInfo.Default.Editors.Contains(EditorName)) {
EditorRegistrationInfo.Default.Editors.Add(new EditorClassInfo(EditorName, typeof(XafEnumEdit),
typeof(RepositoryItemXafEnumEdit), typeof(ImageComboBoxEditViewInfo),
new ImageComboBoxEditPainter(), true, EditImageIndexes.ImageComboBoxEdit, typeof(DevExpress.Accessibility.PopupEditAccessible)));
}
}
protected override RepositoryItem CreateRepositoryItem() {
return new RepositoryItemXafEnumEdit();
}
static RepositoryItemXafEnumEdit() {
RepositoryItemXafEnumEdit.Register();
}
public RepositoryItemXafEnumEdit() {
ReadOnly = true;
TextEditStyle = TextEditStyles.Standard;
ShowDropDown = ShowDropDown.SingleClick;
}
public override void Assign(RepositoryItem item) {
if (item is RepositoryItemXafEnumEdit) {
var source = item as RepositoryItemXafEnumEdit;
if (source != null) {
_application = source._application;
_objectSpace = source._objectSpace;
_model = source._model;
_propertyMemberInfo = source._propertyMemberInfo;
_dataSourceMemberInfo = source._dataSourceMemberInfo;
}
}
base.Assign(item);
}
public override BaseEdit CreateEditor() {
return base.CreateEditor() as XafEnumEdit;
}
public void Init(Type type) {
EnumImagesLoader loader = new EnumImagesLoader(type);
Items.AddRange(loader.GetImageComboBoxItems());
if (loader.Images.Images.Count > 0) {
SmallImages = loader.Images;
}
}
public void Setup(XafApplication application, IObjectSpace objectSpace, IModelMemberViewItem model) {
this._application = application;
this._objectSpace = objectSpace;
this._model = model;
_propertyMemberInfo = null;
_dataSourceMemberInfo = null;
var typeInfo = GetObjectTypeInfo(model);
if (typeInfo == null) return;
_propertyMemberInfo = typeInfo.FindMember(model.PropertyName);
if (!String.IsNullOrEmpty(model.DataSourceProperty)) {
StringBuilder builder = new StringBuilder(model.DataSourceProperty);
var path = _propertyMemberInfo.GetPath();
for (int index = path.Count - 2; index >= 0; index--)
builder.Insert(0, ".").Insert(0, path[index].Name);
_dataSourceMemberInfo = typeInfo.FindMember(builder.ToString());
}
Init(_propertyMemberInfo.MemberType);
}
public override string EditorTypeName { get { return EditorName; } }
public XafApplication Application {
get { return _application; }
}
public IObjectSpace ObjectSpace {
get { return _objectSpace; }
}
public IModelMemberViewItem Model { get { return _model; } }
public IMemberInfo PropertyMemberInfo { get { return _propertyMemberInfo; } }
public IMemberInfo DataSourceMemberInfo { get { return _dataSourceMemberInfo; } }
}
[System.ComponentModel.DesignerCategory("")]
[System.ComponentModel.ToolboxItem(false)]
public partial class XafEnumEdit : ImageComboBoxEdit, IGridInplaceEdit {
private static PropertyDescriptorCollection _imageComboBoxItemProperties;
private object _gridEditingObject;
private IObjectSpace _objectSpace;
internal IList GetDataSource(object forObject) {
CriteriaOperator criteria = null;
if (Properties == null) return null;
IList propertyDataSource =
(Properties.DataSourceMemberInfo != null) ?
Properties.DataSourceMemberInfo.GetValue(forObject) as IList :
null;
IList dataSource = new List<ImageComboBoxItem>();
if (propertyDataSource == null)
for (int i = 0; i < Properties.Items.Count; i++)
dataSource.Add((ImageComboBoxItem)Properties.Items[i]);
else
for (int i = 0; i < Properties.Items.Count; i++) {
var item = (ImageComboBoxItem)Properties.Items[i];
if (propertyDataSource.Contains(item.Value))
dataSource.Add(item);
}
string criteriaString = Properties.Model.DataSourceCriteria;
if (!String.IsNullOrEmpty(criteriaString))
criteria = CriteriaOperator.Parse(criteriaString);
if (!ReferenceEquals(criteria, null)) {
criteria.Accept(new EnumCriteriaParser(
Properties.PropertyMemberInfo.Name,
Properties.PropertyMemberInfo.MemberType));
var filteredDataSource = new ExpressionEvaluator(ImageComboBoxItemProperties, criteria, true).Filter(dataSource);
dataSource.Clear();
foreach (ImageComboBoxItem item in filteredDataSource)
dataSource.Add(item);
}
return dataSource;
}
private void ObjectSpaceObjectChanged(object sender, ObjectChangedEventArgs e) {
if (e.Object == GridEditingObject && (
String.IsNullOrEmpty(e.PropertyName) || (
Properties.DataSourceMemberInfo != null &&
Properties.DataSourceMemberInfo.Name.Equals(e.PropertyName)))) {
}
}
protected override void OnKeyDown(KeyEventArgs e) {
if (e.KeyCode == Keys.Enter) {
ClosePopup();
}
base.OnKeyDown(e);
}
protected override void OnPropertiesChanged() {
base.OnPropertiesChanged();
if (Properties != null)
ObjectSpace = Properties.ObjectSpace;
}
protected override void Dispose(bool disposing) {
if (disposing) {
ObjectSpace = null;
}
base.Dispose(disposing);
}
protected override PopupBaseForm CreatePopupForm() {
return new XafEnumEditPopupForm(this);
}
protected static PropertyDescriptorCollection ImageComboBoxItemProperties {
get {
if (_imageComboBoxItemProperties == null)
_imageComboBoxItemProperties = TypeDescriptor.GetProperties(typeof(ImageComboBoxItem));
return _imageComboBoxItemProperties;
}
}
static XafEnumEdit() {
RepositoryItemXafEnumEdit.Register();
}
public XafEnumEdit() {
Properties.TextEditStyle = TextEditStyles.Standard;
Properties.ReadOnly = true;
Height = WinPropertyEditor.TextControlHeight;
}
public override string EditorTypeName { get { return RepositoryItemXafEnumEdit.EditorName; } }
public object EditingObject {
get { return BindingHelper.GetEditingObject(this); }
}
public new RepositoryItemXafEnumEdit Properties {
get {
return (RepositoryItemXafEnumEdit)base.Properties;
}
}
public object GridEditingObject {
get { return _gridEditingObject; }
set {
if (_gridEditingObject == value) return;
_gridEditingObject = value;
}
}
public IObjectSpace ObjectSpace {
get { return _objectSpace; }
set {
if (_objectSpace != null) _objectSpace.ObjectChanged -= ObjectSpaceObjectChanged;
_objectSpace = value;
if (_objectSpace != null) _objectSpace.ObjectChanged += ObjectSpaceObjectChanged;
}
}
public new XafEnumEditPopupForm PopupForm {
get { return (XafEnumEditPopupForm)base.PopupForm; }
}
}
public partial class XafEnumEdit { }
public class XafEnumEditPopupForm : PopupListBoxForm {
protected override void OnBeforeShowPopup() {
UpdateDataSource();
base.OnBeforeShowPopup();
}
protected override void SetupListBoxOnShow() {
base.SetupListBoxOnShow();
var visibleItems = ListBox.DataSource as IList;
var currentItem = (ImageComboBoxItem)OwnerEdit.SelectedItem;
var currentItemInVisibleItems = visibleItems == null || visibleItems.Contains(currentItem);
var selectedItem = (ImageComboBoxItem)ListBox.SelectedItem;
if (selectedItem != currentItem || !currentItemInVisibleItems)
selectedItem = null;
if (selectedItem == null && currentItemInVisibleItems)
selectedItem = currentItem;
ListBox.SelectedIndex = -1;
ListBox.SelectedItem = selectedItem;
}
public XafEnumEditPopupForm(XafEnumEdit ownerEdit) : base(ownerEdit) { }
public void UpdateDataSource() {
if (Properties == null) return;
var dataSource = OwnerEdit.GetDataSource(OwnerEdit.EditingObject) as IList;
ListBox.DataSource = dataSource != null ? (object)dataSource : (object)Properties.Items;
}
public new XafEnumEdit OwnerEdit { get { return (XafEnumEdit)base.OwnerEdit; } }
public new RepositoryItemXafEnumEdit Properties {
get {
return (RepositoryItemXafEnumEdit)base.Properties;
}
}
}
}
WEB property editor for enum filtering (add it to your ASP.NET module, e.g., Application.Module.Web):
[C#]Open in popup window
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using DevExpress.Data.Filtering;
using DevExpress.Data.Filtering.Helpers;
using DevExpress.ExpressApp;
using DevExpress.ExpressApp.Editors;
using DevExpress.ExpressApp.Model;
using DevExpress.ExpressApp.Utils;
using DevExpress.ExpressApp.Web.Editors.ASPx;
using DevExpress.Persistent.Base;
using DevExpress.Web;
using EnumEditSample.Module.Infrastructure;
namespace Krzysztof.ExpressApp.Web.Framework.Editors.Xaf {
[PropertyEditor(typeof(Enum), EditorAliases.EnumPropertyEditor)]
public class WebFilterableEnumPropertyEditor : ASPxEnumPropertyEditor, IComplexViewItem {
XafApplication application;
IObjectSpace objectSpace;
PropertyInfo dataSourceProperty;
DataSourcePropertyIsNullMode isNullMode = DataSourcePropertyIsNullMode.SelectAll;
string isNullCriteria;
Type propertyType;
public void Setup(IObjectSpace objectSpace, XafApplication application) {
this.application = application;
if (this.objectSpace != null)
this.objectSpace.ObjectChanged -= ObjectSpace_ObjectChanged;
this.objectSpace = objectSpace;
this.objectSpace.ObjectChanged += ObjectSpace_ObjectChanged;
}
public WebFilterableEnumPropertyEditor(Type objectType, IModelMemberViewItem model)
: base(objectType, model) {
PropertyInfo propertyInfo = this.ObjectType.GetProperty(this.PropertyName);
if (propertyInfo != null) {
propertyType = propertyInfo.PropertyType;
foreach (var item in propertyInfo.GetCustomAttributes(false)) {
DataSourcePropertyAttribute propAttr = item as DataSourcePropertyAttribute;
if (propAttr != null && !string.IsNullOrEmpty(propAttr.DataSourceProperty)) {
PropertyInfo dataSourceProperty = this.ObjectType.GetProperty(propAttr.DataSourceProperty);
isNullMode = propAttr.DataSourcePropertyIsNullMode;
isNullCriteria = propAttr.DataSourcePropertyIsNullCriteria;
if (dataSourceProperty != null) {
if (typeof(IEnumerable).IsAssignableFrom(dataSourceProperty.PropertyType) &&
dataSourceProperty.PropertyType.IsGenericType &&
dataSourceProperty.PropertyType.GetGenericArguments()[0].IsAssignableFrom(propertyInfo.PropertyType))
this.dataSourceProperty = dataSourceProperty;
}
}
DataSourceCriteriaAttribute criteriaAttr = item as DataSourceCriteriaAttribute;
if (criteriaAttr != null)
isNullCriteria = criteriaAttr.DataSourceCriteria;
}
}
}
protected override void SetupControl(System.Web.UI.WebControls.WebControl control) {
if (control is ASPxComboBox) {
ASPxComboBox editor = (ASPxComboBox)control;
editor.ShowImageInEditBox = true;
editor.SelectedIndexChanged += EditValueChangedHandler;
FillEditor(editor);
}
}
private void FillEditor(ASPxComboBox editor) {
editor.Items.Clear();
editor.ValueType = GetComboBoxValueType();
IEnumerable dataSource = GetDataSource();
if (this.propertyType.IsGenericType && this.propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) {
editor.Items.Add(CaptionHelper.NullValueText, null);
}
if (dataSource != null)
foreach (object value in dataSource) {
if (value is ListEditItem)
editor.Items.Add(value as ListEditItem);
else
editor.Items.Add(CreateEditItem(value));
}
}
private IEnumerable GetDataSource() {
IEnumerable dataSource = null;
if (dataSourceProperty != null) {
dataSource = dataSourceProperty.GetValue(this.CurrentObject, null) as IEnumerable;
if (dataSource != null) {
bool hasItems = (dataSource).GetEnumerator().MoveNext();
if (!hasItems)
dataSource = null;
}
}
if (dataSource == null) {
if (string.IsNullOrEmpty(isNullCriteria)) {
if (isNullMode == DataSourcePropertyIsNullMode.SelectAll)
return descriptor.Values;
else if (isNullMode == DataSourcePropertyIsNullMode.SelectNothing)
return null;
} else {
CriteriaOperator criteriaOperator = CriteriaOperator.Parse(isNullCriteria);
if (!ReferenceEquals(criteriaOperator, null)) {
dataSource = new List<object>();
foreach (var item in descriptor.Values)
((IList)dataSource).Add(CreateEditItem(item));
criteriaOperator.Accept(new EnumCriteriaParser(
this.PropertyName,
this.propertyType));
var filteredDataSource = new ExpressionEvaluator(ListEditItemProperties, criteriaOperator, true).Filter(dataSource);
((IList)dataSource).Clear();
foreach (ListEditItem item in filteredDataSource)
((IList)dataSource).Add(item);
}
}
}
return dataSource;
}
private IList WrapToList(IEnumerable dataSource) {
if (dataSource == null)
return null;
ArrayList res = new ArrayList();
foreach (var item in dataSource)
res.Add(item);
return res;
}
void ObjectSpace_ObjectChanged(object sender, ObjectChangedEventArgs e) {
if (e.NewValue != e.OldValue && dataSourceProperty != null && e.PropertyName == dataSourceProperty.Name) {
FillEditor(this.Editor);
}
}
private ListEditItem CreateEditItem(object enumValue) {
object value = ConvertEnumValueForComboBox(enumValue);
ImageInfo imageInfo = GetImageInfo(enumValue);
if (imageInfo.IsUrlEmpty) {
return new ListEditItem(descriptor.GetCaption(enumValue), value);
} else {
return new ListEditItem(descriptor.GetCaption(enumValue), value, imageInfo.ImageUrl);
}
}
protected override object GetControlValueCore() {
try {
return base.GetControlValueCore();
} catch {
if (Editor != null)
Editor.SelectedItem = null;
return null;
}
}
private static PropertyDescriptorCollection listEditItemProperties;
protected static PropertyDescriptorCollection ListEditItemProperties {
get {
if (listEditItemProperties == null)
listEditItemProperties = TypeDescriptor.GetProperties(typeof(ListEditItem));
return listEditItemProperties;
}
}
}
}
Sample project for Win and Web solution:
No comments:
Post a Comment