I've got COM object attached to property grid.
Type typeObj = Type.GetTypeFromProgID(progIdService);
var obj = Activator.CreateInstance(typeObj);
propertyGrid1.SelectedObject = obj;
Now I need some way to translate object fields into my language using some translator. I was trying to use wrapper around object but with COM object I have no PropertyInfo, I have only PropertyDescription so I'm still looking for all the possible variants of doing it.
What you could do is reuse the DynamicTypeDescriptor class described in my answer to this question here on SO: PropertyGrid Browsable not found for entity framework created property, how to find it?
like this:
DynamicTypeDescriptor dtp = new DynamicTypeDescriptor(typeObj);
// get current property definition and remove it
var current = dtp.Properties["ThePropertyToChange"];
dtp.RemoveProperty("ThePropertyToChange");
// add a new one, but change its display name
DynamicTypeDescriptor.DynamicProperty prop = new DynamicTypeDescriptor.DynamicProperty(dtp, current, obj);
prop.SetDisplayName("MyNewPropertyName");
dtp.AddProperty(prop);
propertyGrid1.SelectedObject = dtp.FromComponent(obj);
I think you can use reflection to get the property names, although I haven't tried with COM objects yet. Be sure to include the System.Reflection namespace, then you can use it like that:
var props = myComObject.GetType().GetProperties();
foreach (var prop in props)
{
MessageBox(prop.Name);
}
Related
I have two dynamic objects and I'd want to overwrite values of object A with values of object B
The problem is that both are of type dynamic
I managed to extract names of the properties with
TypeDescriptor.GetProperties(oldObject);
but I'm not sure how can I read & set dynamic property of dynamic object
something like oldObject.GetType().GetProperty("Test") won't work since even GetType().GetProperties() return empty collection
Thanks in advance
Below way you can get all the properties and their values.
dynamic dynamicObj = //define it
object obj = dynamicObj;
string[] propertyNames = obj.GetType().GetProperties().Select(p => p.Name).ToArray();
foreach (var name in propertyNames)
{
object value = obj.GetType().GetProperty(name).GetValue(obj, null);
}
Use this for private fields.
obj.GetType().GetProperties(BindingFlags.NonPublic);
I have this property:
[DisplayName("Conexión")]
[TypeConverter(typeof(Converters.DevicesTypeConverter))]
[Description("Conexión con el dispositivo a usar.")]
[Required]
public string Conexion { get; set; }
I need to get the type converter instance of it. I tried with :
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(this);
PropertyDescriptor property = properties.Find("Conexion", false);
var converter = TypeDescriptor.GetConverter(property);
And even with:
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(this);
PropertyDescriptor property = properties.Find("Conexion", false);
var converter = TypeDescriptor.GetConverter(property.PropertyType);
With that, I can only get converter of the property type, that is, the converter for string type, not the actual property converter, DevicesTypeConverter.
Any help please?
EDIT:
What I am trying to do is the following. I have 2 properties in the class that I need to set by mean of a property grid.
"Conexion" property is a list of values that depends on other property.
This dependency works well this way:
When the other property changes, and then I expand the "Conexion" property, GetStandardValuesSupported method on "Conexion" is called. Inside that method I use "context.Instance" to call a method on the object instance that retrieves the list this way:
public List<object> GetDevicesList()
{
if (this.Driver == null)
return null;
var devices = this.Driver.GetList();
if (devices == null)
return null;
return devices.Select(l => (object)l.Value).ToList();
}
The returned list is stored in a private variable in the converter, so this perfectly show the list that depends on the other property.
So far so good. The problem occurs when the object already has value in its properties. Since the list of "Conexion" is exclusive, the property value of it, when I assign it to the property grid, appears empty.
This is obvious because the dependent list only get populated when GetStandardValuesSupported is called, and that happens only when I try to edit the property.
Now I need what I asked in the question. I need to call GetStandardValuesSupported explicitly in object constructor in order to force the dependent list to be loaded before the "Conexion" property is assigned. With that, I am sure the property will appear initialized since the list will have its value.
I think your solution should work but the GetConverter returns null. The problem is only reduced to call the GetStandardValuesSupported() of my custom type converter so I could also use Activator.CreateInstance but the problem is that the type of the converter is null and not the type of DevicesTypeConverter.
You have to jump through several layers to get an instance of the TypeConverter specified in the TypeConverterAttribute (LINQPad demo):
//Get the type you are interested in.
var type = typeof(MyClass);
//Get information about the property you are interested in on the type.
var prop = type.GetProperty("Conexion");
//Pull off the TypeConverterAttribute.
var attr = prop.GetCustomAttribute<TypeConverterAttribute>();
//The attribute only stores the name of the TypeConverter as a string.
var converterTypeName = attr.ConverterTypeName;
// Get the actual Type of the TypeConverter from the string.
var converterType = Type.GetType(converterTypeName);
//Create an instance of the TypeConverter.
var converter = (TypeConverter) Activator.CreateInstance(converterType);
You can use your existing method of getting the converter now that you have the type:
var converter = TypeDescriptor.GetConverter(converterType);
You were close. Once you have the PropertyDescriptor for the property you're interested in, use the Converter property to get the Converter.
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(this);
PropertyDescriptor propertyDescriptor = properties.Find("Conexion", false);
propertyDescriptor.Converter // <- This is what you want
I have a 'Profile' object/class with an IList of 'Addresses', of which, I will only know their type [profile / addresses] at runtime via GetType() / GetProperties() etc., though I wish to .Add to this list e.g.:
var profile = session.Get<ProfileRecord>(1);
dynamic obj = new ExpandoObject();
obj = profile;
obj["Addresses"].Add(addressNew);
This does not work due to:
Cannot apply indexing with [] to an expression of type
'Test.Models.ProfileRecord'.
I've been looking at IDictionary, but have been unsuccessful in my attempts, nor even know if I should be heading down that path - so what is the correct way to go about this? This entire concept is new to me, so please don't over assume my capabilites ;) Many thanks in advance.
You could do it like this if you dont know the type of profile.
var prop = profile.GetType().GetProperty("Addresses").GetValue(profile);
prop.GetType().GetMethod("Add").Invoke(prop, new object[] {1}); // Add the Value to the list
But then you must be sure the List is already initalized.
But i think you should be able to cast your object and set the Property directly like:
if(profile.GetType == typeof (ProfileRecord))
{
var record = (ProfileRecord)profile;
if (profile.Addresses == null)
{
profile.Addresses = new List<Address>();
}
prfile.Addresses.Add(addressNew);
}
In want to add dynamically the properties or methods of a user control from the code behind like this:
foreach (DataRow drModuleSettings in dsModuleSettings.Tables[0].Rows)
{
if (!string.IsNullOrEmpty(dsModuleSettings.Tables[0].Rows[0]["SettingValue"].ToString()))
userControl.Title = dsModuleSettings.Tables[0].Rows[0]["SettingValue"].ToString();
}
The "userControl.Title" is a sample, in fact it should be replaced by such a code:
userControl.drModuleSettings["SettingName"] = dsModuleSettings.Tables[0].Rows[0]["SettingValue"].ToString();
The problem is I don't know how to do this.
Please someone help me.
Thanks!
You will need to use Reflection.
Have a look at the following code and references:
See here: Set object property using reflection
Also, here: http://www.dotnetspider.com/resources/19232-Set-Property-value-dynamically-using-Reflection.aspx:
This code is from the above reference:
// will load the assembly
Assembly myAssembly = Assembly.LoadFile(Environment.CurrentDirectory + "\\MyClassLibrary.dll");
// get the class. Always give fully qualified name.
Type ReflectionObject = myAssembly.GetType("MyClassLibrary.ReflectionClass");
// create an instance of the class
object classObject = Activator.CreateInstance(ReflectionObject);
// set the property of Age to 10. last parameter null is for index. If you want to send any value for collection type
// then you can specify the index here. Here we are not using the collection. So we pass it as null
ReflectionObject.GetProperty("Age").SetValue(classObject, 10,null);
// get the value from the property Age which we set it in our previous example
object age = ReflectionObject.GetProperty("Age").GetValue(classObject,null);
// write the age.
Console.WriteLine(age.ToString());
You could use dynamic properties. Which would mean that, userControl.drModuleSettings will be of type dynamic.
You can then assign it a value at runtime like
userControl.drModuleSettings = new {SomeProperty = "foo", AnotherProperty = "bar"};
More about dynamic keyword and DynamicObject here and here.
Note - Requires C# 4.0 or above.
If I have this string list:
string myObjectString = "MyObject, SetWidth, int, 10, 0, 1";
in which:
- MyObject: the object class
- SetWidth: the property of the object
- int: type of the SetWidth is int
- 10: default value
- 0: object order
- 1: property order
Then how can I construct an object like this:
[ObjectOrder(0)]
public class MyObject:
{
private int _SetWidth = 10;
[PropertyOrder(1)]
public int SetWidth
{
set{_SetWidth=value;}
get{return _SetWidth;}
}
}
So, I would like have something like this:
Object myObject = ConstructAnObject(myObjectString);
and the myObject is an instance of MyObject. Could it be possible in C#?
Thanks in advance.
I think you better use the Object Serialization/Deserialization instead of creating a custom method that basically needs to do the same thing
more info at:
http://msdn.microsoft.com/en-us/library/ms233843.aspx
Here is some quick and dirty code to get you started:
string myObjectString = "MyObject, SetWidth, int, 10, 0, 1";
var info = myObjectString.Split(',');
string objectName = info[0].Trim();
string propertyName = info[1].Trim();
string defaultValue = info[3].Trim();
//find the type
Type objectType = Assembly.GetExecutingAssembly().GetTypes().Where(t=>t.Name.EndsWith(objectName)).Single();//might want to redirect to proper assembly
//create an instance
object theObject = Activator.CreateInstance(objectType);
//set the property
PropertyInfo pi = objectType.GetProperty(propertyName);
object valueToBeSet = Convert.ChangeType(defaultValue, pi.PropertyType);
pi.SetValue(theObject, valueToBeSet, null);
return theObject;
This will find the MyObject, create an object of the proper propertytype, and set the matching property.
If you use C# 4.0, you can use the new dynamic feature.
string myObjectString = "MyObject, SetWidth, int, 10, 0, 1";
String[] properties = myObjectString.Split(',');
dynamic myObj;
myObj.MyObject = (objtect)properties[0];
myObj.SetWidth = Int32.Parse(properties[1]);
// cast dynamic to your object. Exception may be thrown.
MyObject result = (MyObject)myObj;
I don't quite understand why do you need ObjectOrder and PropertyOrder... Once you have their names you probably don't need them, at least for "deserialization"...
Or please advice what is their role?
You definitely can simply do it via reflection:
Split the string by comma (using myString.Split)
Use reflection to find an object within your application:
Find the type with name = splittedString[0] (enumerate all the assemblies within the domain and all the types within each assembly);
Instantiate the type found (using Activator.CreateInstance)
Find the property by name (Using objectType.GetProperty)
Set the property value (using propertyInfo.SetValue)
Return the object
Assuming you need to generate new types there are two possible ways to do so:
Using Reflection Emit
Using CodeDom provider
I think the simpler solution is CodeDom provider. All needed is to generate the source as a string in memory, and then compile the code and instantiate a new instance with Activator. This is a nice example I just found.
The reason I think that CodeDom provider is simpler is that it has shorter setup - no need to generate dynamic module and assembly and then work with type builder and members builder. In addition, it doesn't require working with IL to generate the getter and setter bodies.
An advantage that reflection emit has is performance - dynamic module can add more types to itself even after one of the types was used. CodeDom provider requires creating all the types at once, otherwise it creates a new assembly each time.