I have a set of 'dynamic data' that I need to bind to the GridControl. Up until now, I have been using the standard DataTable class that's part of the System.Data namespace. This has worked fine, but I've been told I cannot use this as it's too heavy for serialization across the network between client & server.
So I thought I could easy replicate a 'cut-down' version of the DataTable class by simply having a type of List<Dictionary<string, object>> whereby the List represents the collection of rows, and each Dictionary represents one row with the column names and values as a KeyValuePair type. I could set up the Grid to have the column DataField properties to match those of the keys in the Dictionary (just like I was doing for the DataTable's column names.
However after doing
gridControl.DataSource = table;
gridControl.RefreshDataSource();
The grid has no data...
I think I need to implement IEnumerator - any help on this would be much appreciated!
Example calling code looks like this:
var table = new List<Dictionary<string,object>>();
var row = new Dictionary<string, object>
{
{"Field1", "Data1"},
{"Field2", "Data2"},
{"Field3", "Data3"}
};
table.Add(row);
gridControl1.DataSource = table;
gridControl1.RefreshDataSource();
Welcome to the wonderful world of System.ComponentModel. This dark corner of .NET is very powerful, but very complex.
A word of caution; unless you have a lot of time for this - you may do well to simply serialize it in whatever mechanism you are happy with, but rehydrate it back into a DataTable at each end... what follows is not for the faint-hearted ;-p
Firstly - data binding (for tables) works against lists (IList/IListSource) - so List<T> should be fine (edited: I misread something). But it isn't going to understand that your dictionary is actually columns...
To get a type to pretend to have columns you need to use custom PropertyDescriptor implementations. There are several ways to do this, depending on whether the column definitions are always the same (but determined at runtime, i.e. perhaps from config), or whether it changes per usage (like how each DataTable instance can have different columns).
For "per instance" customisation, you need to look at ITypedList - this beast (implemented in addition to IList) has the fun task of presenting properties for tabular data... but it isn't alone:
For "per type" customisation, you can look at TypeDescriptionProvider - this can suggest dynamic properties for a class...
...or you can implement ICustomTypeDescriptor - but this is only used (for lists) in very occasional circumstances (an object indexer (public object this[int index] {get;}") and at least one row in the list at the point of binding). (this interface is much more useful when binding discrete objects - i.e. not lists).
Implementing ITypedList, and providing a PropertyDescriptor model is hard work... hence it is only done very occasionally. I'm fairly familiar with it, but I wouldn't do it just for laughs...
Here's a very, very simplified implementation (all columns are strings; no notifications (via descriptor), no validation (IDataErrorInfo), no conversions (TypeConverter), no additional list support (IBindingList/IBindingListView), no abstraction (IListSource), no other other metadata/attributes, etc):
using System.ComponentModel;
using System.Collections.Generic;
using System;
using System.Windows.Forms;
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
PropertyBagList list = new PropertyBagList();
list.Columns.Add("Foo");
list.Columns.Add("Bar");
list.Add("abc", "def");
list.Add("ghi", "jkl");
list.Add("mno", "pqr");
Application.Run(new Form {
Controls = {
new DataGridView {
Dock = DockStyle.Fill,
DataSource = list
}
}
});
}
}
class PropertyBagList : List<PropertyBag>, ITypedList
{
public PropertyBag Add(params string[] args)
{
if (args == null) throw new ArgumentNullException("args");
if (args.Length != Columns.Count) throw new ArgumentException("args");
PropertyBag bag = new PropertyBag();
for (int i = 0; i < args.Length; i++)
{
bag[Columns[i]] = args[i];
}
Add(bag);
return bag;
}
public PropertyBagList() { Columns = new List<string>(); }
public List<string> Columns { get; private set; }
PropertyDescriptorCollection ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors)
{
if(listAccessors == null || listAccessors.Length == 0)
{
PropertyDescriptor[] props = new PropertyDescriptor[Columns.Count];
for(int i = 0 ; i < props.Length ; i++)
{
props[i] = new PropertyBagPropertyDescriptor(Columns[i]);
}
return new PropertyDescriptorCollection(props, true);
}
throw new NotImplementedException("Relations not implemented");
}
string ITypedList.GetListName(PropertyDescriptor[] listAccessors)
{
return "Foo";
}
}
class PropertyBagPropertyDescriptor : PropertyDescriptor
{
public PropertyBagPropertyDescriptor(string name) : base(name, null) { }
public override object GetValue(object component)
{
return ((PropertyBag)component)[Name];
}
public override void SetValue(object component, object value)
{
((PropertyBag)component)[Name] = (string)value;
}
public override void ResetValue(object component)
{
((PropertyBag)component)[Name] = null;
}
public override bool CanResetValue(object component)
{
return true;
}
public override bool ShouldSerializeValue(object component)
{
return ((PropertyBag)component)[Name] != null;
}
public override Type PropertyType
{
get { return typeof(string); }
}
public override bool IsReadOnly
{
get { return false; }
}
public override Type ComponentType
{
get { return typeof(PropertyBag); }
}
}
class PropertyBag
{
private readonly Dictionary<string, string> values
= new Dictionary<string, string>();
public string this[string key]
{
get
{
string value;
values.TryGetValue(key, out value);
return value;
}
set
{
if (value == null) values.Remove(key);
else values[key] = value;
}
}
}
Related
I'm writing a validation engine.
I'm given with an a object payload containing around list of ~40 different properties. Every property will undergo different validation.
The validations include checking if the field is a string and validating if the length exceeds permissible limit set by db and there are conditions to check null values and empty fields as well.
So, I thought of picking the strategy pattern.
Code:
interface IValidationEngine
{
Error Validate(string propName, dynamic propValue);
}
public class StringLengthValidator : IValidationEngine
{
static Dictionary<string, int> sLengths = new Dictionary<string, int>();
public StringLengthValidator()
{
if (sLengths.Count == 0)
{
sLengths = new Dictionary<string, int>(){....};
}
}
public Error Validate(string name, dynamic value)
{
var err = default(Error);
//logic here
return err;
}
}
public class MandatoryValidator : IValidationEngine
{
public Error Validate(string name, dynamic value)
{
var err = default(Error);
//logic here
return err;
}
}
public class MandatoryStringLengthValidator : IValidationEngine
{
public Error Validate(string name, dynamic value)
{
var e = default(Error);
if (value == null || (value.GetType() == typeof(string) && string.IsNullOrWhiteSpace(value)))
{
e = new Error()
{
//.. err info
};
}
else
{
StringLengthValidator sl = new StringLengthValidator();
e = sl.Validate(name, value);
}
return e;
}
}
There is another class which I named it ValidationRouter. The job of this is to route to the specific validator (Think of this as a Strategy as per pattern).
I wrote the initial router to have a dictionary of keys and its respective objects map so that whatever comes in will match its key and calls its appropriate validate() method on the dictionary value. But as adding keys and values with new object creation. I think the class will take lot of memory as I've the object creation in the constructor.
So, I've added Lazy to the object creation and it ended up like this
Here is the code for router
public class ValidationRouter
{
public Dictionary<string, Lazy<IValidationEngine>> strategies = new Dictionary<string, Lazy<IValidationEngine>>();
public ValidationRouter()
{
var mandatoryStringLength = new Lazy<IValidationEngine>(() => new MandatoryStringLengthValidator());
var mandatory = new Lazy<IValidationEngine>(() => new MandatoryValidator());
var stringLength = new Lazy<IValidationEngine>(() => new StringLengthValidator());
strategies.Add("position", mandatoryStringLength);
strategies.Add("pcode", stringLength);
strategies.Add("username", mandatoryStringLength);
strategies.Add("description", stringLength);
strategies.Add("sourcename", stringLength);
//OMG: 35 more fields to be added to route to specific routers
}
public Error Execute(string name, dynamic value)
{
//Find appropriate field and route to its strategy
var lowered = name.ToLower();
if (!strategies.ContainsKey(lowered)) return default(Error);
return strategies[lowered].Value.Validate(name, value);
}
}
As you can see I need to add 35 more keys to dictionaries with appropriate strategies in the constructor.
Is the approach correct or is there any better way of routing to specific validator algorithms ?
I thought of object creation to be done by factory pattern with Activator.CreateInstance but not sure how to achieve as each of my properties will have different strategies.
Any ideas would be appreciated.
I have several ComboBox controls, with DropDownStyle set to DropDownList. The items that are selected are enum values, but I want "friendly" descriptions of these to be displayed, i.e. with spaces and not camel case.
I want the combo box to be "two-way" bound to the data object: if the data object changes its property it alters the combo box, and vice versa.
I can do this easily with strings but the problem is I am binding the controls to enum properties in the objects, so I want the Items collection of the Combo Box to contain actual enums. This obviously isn't going to work.
Solution 1: textual properties
I can create extra properties in my object which are textual, and map those to the enum values. This is a bit messy though as I am including things in my business logic layer which really belong in the UI. In that business logic layer they should be enums and not strings.
Solution 2: event handlers
Another alternative is to use event handlers so that when the user changes the option it gets the selected item text and finds the appropriate enum value, then sets this in the object. This is only one way binding though.
Attempted Solution 3
public class BusinessObject
{
private NumberCategory category;
public NumberCategory Category
{
get
{
return category;
}
set
{
category = value;
}
}
}
public enum NumberCategory
{
[Description("Negative Number")]
NegativeNumber,
[Description("Zero")]
Zero,
[Description("One")]
One,
[Description("Prime Number")]
PrimeNumber,
[Description("Composite Number")]
CompositeNumber,
}
public class EnumDescriptionAdapter
{
private readonly BusinessObject businessObject;
public EnumDescriptionAdapter(BusinessObject businessObject)
{
this.businessObject = businessObject;
}
public string CategoryValue
{
get
{
//get the enum from businessObject and convert to a string
return EnumUtils.GetDescription(businessObject.Category);
}
set
{
//get the string, convert to an enum and set it in BusinessObject
businessObject.Category = EnumUtils.GetValueFromDescription<NumberCategory>(value);
}
}
}
public static class EnumUtils
{
public static T GetValueFromDescription<T>(string description)
{
var type = typeof(T);
if (!type.IsEnum) throw new InvalidOperationException();
foreach (var field in type.GetFields())
{
var attribute = Attribute.GetCustomAttribute(field,
typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attribute != null)
{
if (attribute.Description == description)
return (T)field.GetValue(null);
}
else
{
if (field.Name == description)
return (T)field.GetValue(null);
}
}
throw new ArgumentException("Not found.", "description");
// or return default(T);
}
public static string GetDescription(Enum value)
{
Type type = value.GetType();
string name = Enum.GetName(type, value);
if (name != null)
{
FieldInfo field = type.GetField(name);
if (field != null)
{
DescriptionAttribute attr =
Attribute.GetCustomAttribute(field,
typeof(DescriptionAttribute)) as DescriptionAttribute;
if (attr != null)
{
return attr.Description;
}
}
}
return null;
}
}
public partial class Form1 : Form
{
public BusinessObject businessObject;
public Form1()
{
InitializeComponent();
string[] descriptions = Enum.GetValues(typeof(NumberCategory)).Cast<NumberCategory>().Select(e => EnumUtils.GetDescription(e)).ToArray();
comboBox1.DataSource = descriptions;
businessObject = new BusinessObject();
EnumDescriptionAdapter adapter = new EnumDescriptionAdapter(businessObject);
comboBox1.DataBindings.Add(new Binding("SelectedItem", adapter, "CategoryValue"));
}
private void button1_Click(object sender, EventArgs e)
{
businessObject.Category = NumberCategory.PrimeNumber;
}
}
I put a button (button1) and a combo box (comboBox1) on my form. When I change the combo box selected item, it does fire the setter in EnumDescriptionAdapter.CategoryValue and change the businessObject. However, the reverse is not true: if I press the button it changes the businessObject but doesn't alter the selected item in comboBox1.
I don't know if it is more elegant but you can create a class with 2 properties, one for showing and one as value. You then populate a list of such created, one way or another, from your enums.
You get a star for recognising that decorating business layer stuff with presentation layer stuff is not considered good practice.
I have a (string, object) dictionary, object (class) has some values including data type which is defined by enum. I need a GetItemValue method that should return dictionary item's value. So return type must be the type which is defined in item object.
Class Item
{
String Name;
DataValueType DataType;
Object DataValue;
}
private Dictionary<string, Item> ItemList = new Dictionary<string, Item>();
void Main()
{
int value;
ItemList.Add("IntItem", new Item("IntItem", DataValueType.TInt, 123));
value = GetItemValue("IntItem"); // value = 123
}
What kind of solution can overcome this problem?
Best Regards,
You can use Generic Classes
Class Item<T>
{
String Name;
T DataTypeObject;
Object DataValue;
public T GetItemValue()
{
//Your code
return DataTypeObject;
}
}
A better solution would be to introduce an interface that you make all the classes implement. Note that the interface doesn't necessarily have to specify any behavior:
public interface ICanBePutInTheSpecialDictionary {
}
public class ItemTypeA : ICanBePutInTheSpecialDictionary {
// code for the first type
}
public class ItemTypeB : ICanBePutInTheSpecialDictionary {
// code for the second type
}
// etc for all the types you want to put in the dictionary
To put stuff in the dictionary:
var dict = new Dictionary<string, ICanBePutInTheSpecialDictionary>();
dict.add("typeA", new ItemTypeA());
dict.add("typeB", new ItemTypeB());
When you need to cast the objects to their specific types, you can either use an if-elseif-block, something like
var obj = dict["typeA"];
if (obj is ItemTypeA) {
var a = obj as ItemTypeA;
// Do stuff with an ItemTypeA.
// You probably want to call a separate method for this.
} elseif (obj is ItemTypeB) {
// do stuff with an ItemTypeB
}
or use reflection. Depending on how many choices you have, either might be preferrable.
If you have a 'mixed bag' you could do something like this...
class Item<T>
{
public String Name { get; set; }
public DataValueType DataType { get; set; }
public T DataValue { get; set; }
}
class ItemRepository
{
private Dictionary<string, object> ItemList = new Dictionary<string, object>();
public void Add<T>(Item<T> item) { ItemList[item.Name] = item; }
public T GetItemValue<T>(string key)
{
var item = ItemList[key] as Item<T>;
return item != null ? item.DataValue : default(T);
}
}
and use it like...
var repository = new ItemRepository();
int value;
repository.Add(new Item<int> { Name = "IntItem", DataType = DataValueType.TInt, DataValue = 123 });
value = repository.GetItemValue<int>("IntItem");
If you have just a couple types - you're better off with Repository<T>.
I found a solution exactly what I want. Thanks to uncle Google.
Thanks all of you for your kind interest.
public dynamic GetValue(string name)
{
if (OpcDataList[name].IsChanged)
{
OpcReflectItem tmpItem = OpcDataList[name];
tmpItem.IsChanged = false;
OpcDataList[name] = tmpItem;
}
return Convert.ChangeType(OpcDataList[name].ItemValue.Value, OpcDataList[name].DataType);
}
I'm trying to add items to a listbox,combobox, radiolist using reflection. The code I have at the moment is as follows:
public static Control ConfigureControl(Control control, ControlConfig ctrlconf)
{
if (control is TextBox)
{
// ...
}
else
{
// get the properties of the control
//
Type controlType = control.GetType();
PropertyInfo[] controlPropertiesArray = controlType.GetProperties();
foreach (PropertyInfo controlProperty in controlPropertiesArray)
{
if (controlProperty.Name == "Items" && controlProperty.PropertyType == typeof(ListItemCollection))
{
object instance = Activator.CreateInstance(controlProperty.PropertyType);
MethodInfo addMethod = controlProperty.PropertyType.GetMethod("Add", new Type[] { typeof(ListItem)} );
List<string> popValues = new List<string>(ctrlconf.PopulatedValues.Split(';'));
if (popValues.Count.Equals(0))
{
throw new ArgumentException("No values found for control");
}
else
{
foreach (string val in popValues)
{
addMethod.Invoke(instance, new object[] { new ListItem(val, val) });
}
}
}
}
}
return control;
}
The code above populates the listitemcollection which I have instantiated using Activator.CreateInstance, however I'm not sure how to add it to the ListBox.
Any help would be great.
Thanks,
Peter
You don't need or want to instantiate the collection object: that's already done by the control. Instead, you need to get the existing collection object, then add to that:
if (controlProperty.Name == "Items" && controlProperty.PropertyType == typeof(ListItemCollection))
{
object instance = controlProperty.GetValue(control, null);
// ... now go on and add to the collection ...
}
However, as others have noted, this may not be the best way to approach the problem. Instead, consider implementing adapter or strategy for the various controls you want to support e.g. RadioButtonListItemAdder, ListControlItemAdder, etc., which all conform to a common interface. Each type of XxxItemAdder can implement its own strongly-typed code, suitable for the type of control it's responsible for adding items to. This might look something like the following:
public interface IItemAdder
{
void AddItem(string value);
}
public class ListControlItemAdder : IItemAdder
{
private readonly ListControl _listControl;
public ListControlItemAdder(ListControl listControl)
{
_listControl = listControl;
}
public void AddItem(string value)
{
_listControl.Items.Add(value); // or new ListItem(value, value) per your original code
}
}
public class RadioButtonListItemAdder : IItemAdder
{
// ...
public void AddItem(string value)
{
// do whatever you have to do to add an item to a list of RadioButtons
}
}
public static IItemAdder CreateItemAdderFor(Control control)
{
if (control is ListControl)
return new ListControlItemAdder((ListControl)control);
else if (control is RadioButtonList)
return new RadioButtonListItemAdder((RadioButtonList)control);
// etc. to cover other cases
}
public static Control ConfigureControl(Control control, ...)
{
// ... omitting code that looks like your existing code ...
IItemAdder itemAdder = CreateItemAdderFor(control);
foreach (string val in popValues)
itemAdder.AddItem(val);
}
This is a really untidy implementation but hopefully gives you the idea of how you can separate out each of the individual control-specific implementations into small, nicely separated classes.
I would like to get property name when I'm in it via reflection. Is it possible?
I have code like this:
public CarType Car
{
get { return (Wheel) this["Wheel"];}
set { this["Wheel"] = value; }
}
And because I need more properties like this I would like to do something like this:
public CarType Car
{
get { return (Wheel) this[GetThisPropertyName()];}
set { this[GetThisPropertyName()] = value; }
}
Since properties are really just methods you can do this and clean up the get_ returned:
class Program
{
static void Main(string[] args)
{
Program p = new Program();
var x = p.Something;
Console.ReadLine();
}
public string Something
{
get
{
return MethodBase.GetCurrentMethod().Name;
}
}
}
If you profile the performance you should find MethodBase.GetCurrentMethod() is miles faster than StackFrame. In .NET 1.1 you will also have issues with StackFrame in release mode (from memory I think I found it was 3x faster).
That said I'm sure the performance issue won't cause too much of a problem- though an interesting discussion on StackFrame slowness can be found here.
I guess another option if you were concerned about performance would be to create a Visual Studio Intellisense Code Snippet that creates the property for you and also creates a string that corresponds to the property name.
Slightly confusing example you presented, unless I just don't get it.
From C# 6.0 you can use the nameof operator.
public CarType MyProperty
{
get { return (CarType)this[nameof(MyProperty)]};
set { this[nameof(MyProperty)] = value]};
}
If you have a method that handles your getter/setter anyway, you can use the C# 4.5 CallerMemberName attribute, in this case you don't even need to repeat the name.
public CarType MyProperty
{
get { return Get<CarType>(); }
set { Set(value); }
}
public T Get<T>([CallerMemberName]string name = null)
{
return (T)this[name];
}
public void Set<T>(T value, [CallerMemberName]string name = null)
{
this[name] = value;
}
I'd like to know more about the context in which you need it since it seems to me that you should already know what property you are working with in the property accessor. If you must, though, you could probably use MethodBase.GetCurrentMethod().Name and remove anything after get_/set_.
Update:
Based on your changes, I would say that you should use inheritance rather than reflection. I don't know what data is in your dictionary, but it seems to me that you really want to have different Car classes, say Sedan, Roadster, Buggy, StationWagon, not keep the type in a local variable. Then you would have implementations of methods that do the proper thing for that type of Car. Instead of finding out what kind of car you have, then doing something, you then simply call the appropriate method and the Car object does the right thing based on what type it is.
public interface ICar
{
void Drive( decimal velocity, Orientation orientation );
void Shift( int gear );
...
}
public abstract class Car : ICar
{
public virtual void Drive( decimal velocity, Orientation orientation )
{
...some default implementation...
}
public abstract void Shift( int gear );
...
}
public class AutomaticTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
public class ManualTransmission : Car
{
public override void Shift( int gear )
{
...some specific implementation...
}
}
Use MethodBase.GetCurrentMethod() instead!
Reflection is used to do work with types that can't be done at compile time. Getting the name of the property accessor you're in can be decided at compile time so you probably shouldn't use reflection for it.
You get use the accessor method's name from the call stack using System.Diagnostics.StackTrace though.
string GetPropertyName()
{
StackTrace callStackTrace = new StackTrace();
StackFrame propertyFrame = callStackTrace.GetFrame(1); // 1: below GetPropertyName frame
string properyAccessorName = propertyFrame.GetMethod().Name;
return properyAccessorName.Replace("get_","").Replace("set_","");
}
FWIW I implemented a system like this:
[CrmAttribute("firstname")]
public string FirstName
{
get { return GetPropValue<string>(MethodBase.GetCurrentMethod().Name); }
set { SetPropValue(MethodBase.GetCurrentMethod().Name, value); }
}
// this is in a base class, skipped that bit for clairty
public T GetPropValue<T>(string propName)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
return GetAttributeValue<T>(attributeName);
}
public void SetPropValue(string propName, object value)
{
propName = propName.Replace("get_", "").Replace("set_", "");
string attributeName = GetCrmAttributeName(propName);
SetAttributeValue(attributeName, value);
}
private static Dictionary<string, string> PropToAttributeMap = new Dictionary<string, string>();
private string GetCrmAttributeName(string propertyName)
{
// keyName for our propertyName to (static) CrmAttributeName cache
string keyName = this.GetType().Name + propertyName;
// have we already done this mapping?
if (!PropToAttributeMap.ContainsKey(keyName))
{
Type t = this.GetType();
PropertyInfo info = t.GetProperty(propertyName);
if (info == null)
{
throw new Exception("Cannot find a propety called " + propertyName);
}
object[] attrs = info.GetCustomAttributes(false);
foreach (object o in attrs)
{
CrmAttributeAttribute attr = o as CrmAttributeAttribute ;
if (attr != null)
{
// found it. Save the mapping for next time.
PropToAttributeMap[keyName] = attr.AttributeName;
return attr.AttributeName;
}
}
throw new Exception("Missing MemberOf attribute for " + info.Name + "." + propertyName + ". Could not auto-access value");
}
// return the existing mapping
string result = PropToAttributeMap[keyName];
return result;
}
There's also a custom attribute class called CrmAttributeAttribute.
I'd strongly recommend against using GetStackFrame() as part of your solution, my original version of the solution was originally the much neater:
return GetPropValue<string>();
But it was 600x slower than the version above.
Solution # 1
var a = nameof(SampleMethod); //a == SampleMethod
var b = nameof(SampleVariable); //b == SampleVariable
var c = nameof(SampleProperty); //c == SampleProperty
Solution # 2
MethodBase.GetCurrentMethod().Name; // Name of method in which you call the code
MethodBase.GetCurrentMethod().Name.Replace("set_", "").Replace("get_", ""); // current Property
Solution # 3
from StackTrace:
public static class Props
{
public static string CurrPropName =>
(new StackTrace()).GetFrame(1).GetMethod().Name.Replace("set_", "").Replace("get_", "");
public static string CurrMethodName =>
(new StackTrace()).GetFrame(1).GetMethod().Name;
}
you just need to call Props.CurrPropName or Props.CurrMethodName
Solution # 4
Solution for .NET 4.5+:
public static class Props
{
public static string GetCallerName([System.Runtime.CompilerServices.CallerMemberName] String propertyName = "")
{
return propertyName;
}
}
usage: Props.GetCallerName();
Yes, it is!
string test = "test string";
Type type = test.GetType();
PropertyInfo[] propInfos = type.GetProperties();
for (int i = 0; i < propInfos.Length; i++)
{
PropertyInfo pi = (PropertyInfo)propInfos.GetValue(i);
string propName = pi.Name;
}
Try using System.Diagnostics.StackTrace to reflect on the call stack. The property should be somewhere in the call stack (probably at the top if you're calling it directly from the property's code).