How realize this method in c#:
public static void SetParam(string element, string property, dynamic value){
// Do something
}
// Usage:
setParam("textBox1","Text","Hello");
In JavaScript this looks:
function SetParam(element, property, value) {
document.getElementById(element)[property]=value;
}
// Usage:
SetParam("textBox","value","Hello");
Perhaps the following works for you.
public void SetParam(string element, string property, dynamic value)
{
FieldInfo field = typeof(Form1).GetField(element, BindingFlags.NonPublic | BindingFlags.Instance);
object control = field.GetValue(this);
control.GetType().GetProperty(property).SetValue(control, value, null);
}
Replace Form1 with the form class that contains the controls you want to modify.
Edit: After having read Blachshma's answer, I realize that you'll have to put
using System.Reflection;
at the top of the file.
I also assumed it's for a Windows Forms Application.
Lastly, a better way to get a reference to the control is probably to use the Form.Controls property like Greg suggested.
If I understand your question correctly, this can be done with a little help of Reflection ...
Start by adding a: using System.Reflection; to the top of your cs file.
Since I don't know if you're using WPF or Winforms - here are 2 examples...
WPF:
You can use this version of SetParam:
private void SetParam(string name, string property, dynamic value)
{
// Find the object based on it's name
object target = this.FindName(name);
if (target != null)
{
// Find the correct property
Type type = target.GetType();
PropertyInfo prop = type.GetProperty(property);
// Change the value of the property
prop.SetValue(target, value);
}
}
Usage:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
SetParam("textbox", "Text", "Hello");
Where textbox is declared like this:
<TextBox x:Name="textbox" />
For Winforms just change SetParam to this:
private void SetParam(string name, string property, dynamic value)
{
// Find the object based on it's name
object target = this.Controls.Cast<Control>().FirstOrDefault(c => c.Name == name);
if (target != null)
{
// Find the correct property
Type type = target.GetType();
PropertyInfo prop = type.GetProperty(property);
// Change the value of the property
prop.SetValue(target, value);
}
}
Assuming that the "element" variable is the I'd of the control then using reflection:
PropertyInfo propertyInfo = form1.Controls.Where(c => c.id == element).FirstOrDefault().GetType().GetProperty(property,
BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
if (propertyInfo != null)
{
if (propertyInfo.PropertyType.Equals(value.GetType()))
propertyInfo.SetValue(control, value, null);
else
throw new Exception("Property DataType mismatch, expecting a " +
propertyInfo.PropertyType.ToString() + " and got a " +
value.GetType().ToString());
}
}
Related
I'm working on a business application that use the PropertyGrid. My project leader want me to localize the texts in the PropertyGrid at runtime. Hurray!!! irony
I have tried many days to localize the PropertyGrid. But I have trouble changing the attributes Description and Category at runtime. Changing the DisplayName works fine.
I have made a simple example to reproduce the issue: Create a Windows Form application and from the ToolBox add a PropertyGrid and a Button with default settings.
Here is the class I would like to display in the PropertyGrid:
class Person
{
int age;
public Person()
{
age = 10;
}
[Description("Person's age"), DisplayName("Age"), Category("Fact")]
public int Age
{
get { return age; }
}
}
In the Form's constructor; I create the Person object and display it in the PropertyGrid.
public Form1()
{
InitializeComponent();
propertyGrid1.SelectedObject = new Person();
}
The button is used to change the DisplayName, Description and Category attributes at runtime.
private void button1_Click(object sender, EventArgs e)
{
SetDisplayName();
SetDescription();
SetCategory();
propertyGrid1.SelectedObject = propertyGrid1.SelectedObject; // Reset the PropertyGrid
}
The SetDisplayName() method works fine and actually changes the DisplayName of the property in runtime!
private void SetDisplayName()
{
Person person = propertyGrid1.SelectedObject as Person;
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(person)["Age"];
DisplayNameAttribute attribute = descriptor.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
FieldInfo field = attribute.GetType().GetField("_displayName", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(attribute, "The age");
}
SetDescription() and SetCategory() methods are almost identical to the SetDisplayName() method, except for some type changes and strings to access the private member of each attributes.
private void SetDescription()
{
Person person = propertyGrid1.SelectedObject as Person;
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(person)["Age"];
DescriptionAttribute attribute = descriptor.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
FieldInfo field = attribute.GetType().GetField("description", BindingFlags.NonPublic |BindingFlags.Instance);
field.SetValue(attribute, "Age of the person");
}
private void SetCategory()
{
Person person = propertyGrid1.SelectedObject as Person;
PropertyDescriptor descriptor = TypeDescriptor.GetProperties(person)["Age"];
CategoryAttribute attribute = descriptor.Attributes[typeof(CategoryAttribute)] as CategoryAttribute;
FieldInfo[] fields = attribute.GetType().GetFields(BindingFlags.NonPublic | BindingFlags.Instance);
FieldInfo field = attribute.GetType().GetField("categoryValue", BindingFlags.NonPublic | BindingFlags.Instance);
field.SetValue(attribute, "Info");
}
Both SetDescription() and SetCategory() methods compile and run but don't effext the ProperytGrid. After the last line of each method you can use the IntelliSense to see that the the Attribute object (DescriptionAttribute and CategoryAttribute) has a member that has changed.
After running these three methods and resetting the PropertyGrid (see button1 click method); the PropertyGrid has only changed the DisplayName attribute. The Description and the Category attributes are unchanged.
I would really like some help to solve this issue. Please any suggestion or solutions?
Note 1:
I don't want any responses saying that this is impossible and the attributes can only be set at design time. That is not true! This article from CodeProject.com show an example how to localize the PropertyGrid and to change the attributes in runtime. Unfortunately I have problem scoping the example for those parts I need to solve this issue.
Note 2:
I would like to avoid using resouce files. This is due to the localization is located in different language files. Each file contain a bunch of indices, each with a string value. All indices and string values are loaded into Dictionary object. To access a string the index is used to access it. I most, unfortunately, use this solution.
Best regards,
/Mc_Topaz
Here is a good article for Globalized-property-grid
You can give many resource file for the Person ,than will the propery-grid will localize.
Here is three step:
inherit from GlobalizedObject
Give the resource file for Person with the same name (eg.Person.zh-cn.resx)
change the thread's cuture which you want to display.
You can try ,Good Luck!
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:
public Form1()
{
InitializeComponent();
Person p = new Person();
DynamicTypeDescriptor dt = new DynamicTypeDescriptor(typeof(Person));
propertyGrid1.SelectedObject = dt.FromComponent(p);
}
private void button1_Click(object sender, EventArgs e)
{
DynamicTypeDescriptor dt = (DynamicTypeDescriptor)propertyGrid1.SelectedObject;
DynamicTypeDescriptor.DynamicProperty dtp = (DynamicTypeDescriptor.DynamicProperty)dt.Properties["Age"];
dtp.SetDisplayName("The age");
dtp.SetDescription("Age of the person");
dtp.SetCategory("Info");
propertyGrid1.Refresh();
}
xudong125 answer solves the issue! I managed to work around the resource files solution by using a static source instead. It's to complicated to explain...
But creating classes implementing ICustomTypeDescriptor and PropertyDescriptor is the way to go.
The key was to override DisplayName, Description and Category methods in the sub class of the PropertyDescriptor class. In these overriden methods I pointed to a public static source and managed to get the strings I wanted.
/Mc_Topaz
I have a different reason to change the property description and found a fairly crude but much simpler solution for just correcting the description that is shown in the grid. Advantage for me was that the class of the object shown in the property grid required much less change.
My situation was the following: I have two boolean properties A and B, where B only can be used if A is set. If A is False, I want to make B read-only and set its description to something like "This property can only be used if you set 'A' to True". In the object code I set the Description attribute of B to this message, similar to how Mc_Topaz does that.
To only set the description that is shown for the selected property to its correct current value, I use the following SelectedGridItemChanged event handler for my PropertyGrid named pgConfig:
private void pgConfig_SelectedGridItemChanged(object sender, SelectedGridItemChangedEventArgs e)
{
GridItem giSelected = e.NewSelection;
if ((giSelected != null) && (giSelected.PropertyDescriptor != null))
{
string sDescription = GetCurrentPropertyDescription(giSelected.PropertyDescriptor.Name);
if ((sDescription != null) && (sDescription != giSelected.PropertyDescriptor.Description))
{
MethodInfo miSetStatusBox = pgConfig.GetType().GetMethod("SetStatusBox", BindingFlags.NonPublic | BindingFlags.Instance);
if (miSetStatusBox != null)
miSetStatusBox.Invoke(pgConfig, new object[] { giSelected.PropertyDescriptor.DisplayName, sDescription });
}
}
}
In the code sample, GetCurrentPropertyDescription is a private function that retrieves the current property description of the object being shown in the property grid (m_da.Config in my case):
private string GetCurrentPropertyDescription(string sPropertyName)
{
PropertyDescriptor oPropDescriptor = TypeDescriptor.GetProperties(m_da.Config.GetType())[sPropertyName];
if (oPropDescriptor != null)
{
DescriptionAttribute oDescriptionAttr = (DescriptionAttribute)oPropDescriptor.Attributes[typeof(DescriptionAttribute)];
if (oDescriptionAttr != null)
return oDescriptionAttr.Description;
}
return null;
}
My solution is less suitable than huoxudong125's if you want full globalization, but if you just want dynamic descriptions for some of your properties without changing the inheritance of the object being shown, it is an option.
Disadvantage of my method is that the underlying cached PropertyDescriptor objects of the grid are never updated, so SetStatusBox will always be called twice if a property with changed description is selected, which is inefficient.
The solution of huoxudong125 is one possible solution. I'd like to offer another one (but without talking about how to change the culture stuff at runtime - you can google that yourself ;) ). For myself I started with using localized subclasses for DisplayName, Description and Category.
As we know, DisplayName does update to current culter when PropertyGrid is updated, but Description and Category do not. I think the reason for this is on reflection level, when PropertyGrid requests category and description. As you can see, those values are cached on first read but displayName is not. To tackle that I developed two solution (where the first one is weird and I do not understand why that works myself..). Both revolve around an extra TypeDescriptionProvider
The base
First goes the custom TypeDescriptionProvider, which can be bound to any class via attribute:
internal class UpdateableGlobalizationDescriptionProvider<TTargetType> : TypeDescriptionProvider
{
private static TypeDescriptionProvider defaultTypeProvider = TypeDescriptor.GetProvider(typeof(TTargetType));
public UpdateableGlobalizationDescriptionProvider() : base(defaultTypeProvider) { }
public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance)
{
var result = base.GetTypeDescriptor(objectType, instance);
return new ForcedGlobalizationTypeDescriptor(result);
}
}
First solution
This one revolves around "just get it done"... Add a CustomTypeDescriptor implementation, which wraps original PropertyDescriptor instances with the custom ones:
internal class ForcedGlobalizationTypeDescriptor : CustomTypeDescriptor
{
readonly ICustomTypeDescriptor inner;
public ForcedGlobalizationTypeDescriptor(ICustomTypeDescriptor typeDescriptor) : base(typeDescriptor)
{
inner = typeDescriptor;
}
public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
{
// First solution
var result = base.GetProperties(attributes);
var transformed = result.OfType<PropertyDescriptor>().Select(d => new ForcedPropertyDescriptor(d)).ToArray();
return new PropertyDescriptorCollection(transformed);
}
}
and outer the PropertyDesciptor simply returns values from the wrapped PropertyDescriptor. The simplest implementation for PropertyDescriptor I found - tell me, if there is a shorter one, please.
internal class ForcedPropertyDescriptor : PropertyDescriptor
{
private PropertyDescriptor innerDescriptor;
public ForcedPropertyDescriptor(PropertyDescriptor descriptor) : base(descriptor)
{
innerDescriptor = descriptor;
}
// important:
public override string Category => base.Category;
public override string Description => base.Description;
public override Type ComponentType => innerDescriptor.ComponentType;
public override bool IsReadOnly => innerDescriptor.IsReadOnly;
public override Type PropertyType => innerDescriptor.PropertyType;
public override bool CanResetValue(object component) => innerDescriptor.CanResetValue(component);
public override object GetValue(object component) => innerDescriptor.GetValue(component);
public override void ResetValue(object component) => innerDescriptor.ResetValue(component);
public override void SetValue(object component, object value) => innerDescriptor.SetValue(component, value);
public override bool ShouldSerializeValue(object component) => innerDescriptor.ShouldSerializeValue(component);
}
I think it works, because for every read of category or description there is a new ForcedPropertyDescriptor, which has not cached the value, yet. At the same time this is a drawback: for like every request on the Category or Description propery a new instance of ForcedPropertyDescriptor is created, while Microsoft's implementation seems to cache craeated PropertyDescriptors somewehere.
Second solution
To avoid that instance creation every time, I simply stored every seen ProperyDescriptor created by ForcedGlobalizationTypeDescriptor in a set. And as soon as a localization change appears, that set gets called to reset it's items cached values:
internal class DescriptorReset
{
public static DescriptorReset Default { get; } = new DescriptorReset();
private HashSet<MemberDescriptor> descriptors = new HashSet<MemberDescriptor>();
public void Add(MemberDescriptor descriptor)
{
descriptors.Add(descriptor);
}
private void RunUpdate()
{
if (descriptors.Count == 0)
return;
FieldInfo category, description;
category = typeof(MemberDescriptor).GetField(nameof(category), BindingFlags.NonPublic | BindingFlags.Instance);
description = typeof(MemberDescriptor).GetField(nameof(description), BindingFlags.NonPublic | BindingFlags.Instance);
foreach (var descriptor in descriptors)
{
category.SetValue(descriptor, null);
description.SetValue(descriptor, null);
}
}
}
The RunUpdate method uses Reflection to reset inner fields to null, so on the next call to corresponding properties the localized values are read again.
All you need now is some magic to call RunUpdate at the right moment. For myself I have a class in my core solution, which provides a method to set a new CultureInfo. When called, it sets the default ui culture and the default culture to the new CultureInfo and raises two events: the first one is to update all internal logic and the second one is for everything based on internal logic, like the GUI.
And since I do not know where and how long Microsoft's PropertyDescriptors are stored, I created a HashSet with WeakReference (based on WeakHashTable) to store corresponding references.
Usage
Simply append the DescriptionProvider class to your class shown in PropertyGrid:
[LocalizedDescription(nameof(MyClass), typeof(MyTextResource))]
[TypeDescriptionProvider(typeof(ForcedGlobalizationTypeDescriptor<MyClass>))]
class MyClass
{
// ...
The way your LocalizedDescription works, depends on you...
Is there a way in C# to create a field which is a reference to another field which is a value type?
class myClass
{
bool b1;
public void method1(ref bool b)
{
b1 = b;
}
}
I want b1 to reference the value of b, just as b references the value of the original argument, so that changes to b1 will affect the original argument.
EDIT:
What I’m trying to achieve is a myCheckBox class which automatically updates a field. See: How do I change a value argument from within an event handler?
Sure! Take a look at Eric's answer to this question:
Setting a ref to a member field in C#
As others have pointed out, you cannot store a reference to a variable
in a field in C#, or indeed, any CLR language.
Of course you can capture a reference to a class instance that
contains a variable easily enough
Well... there is a very contort way :) of course.
That is, using reflection!
You cannot get the address of a field, but we can use reflection.
Reflection is slower than accessing directly a field, i warn you.
And really, accessing private fields of other classes is a really bad practice!
Is however useful sometime for some dirty hacks when you don't have control of code written by other people.
Here the example, but i keep saying, it is not a good practice, is here only for curiosity and for educational purposes!
Fine another way to access your field, using properties or using a class that modify your properties.
// Our FieldReference class that internally uses reflection to get or set a field value.
public class FieldReference<T>
{
private object ownerObject;
private FieldInfo fieldInfo;
public FieldReference(object ownerObject, string fieldName)
{
this.ownerObject = ownerObject;
this.fieldInfo = ownerObject.GetType().GetField(fieldName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
}
public FieldReference(object ownerObject, FieldInfo fieldInfo)
{
this.ownerObject = ownerObject;
this.fieldInfo = fieldInfo;
}
public T Value
{
get { return (T)this.fieldInfo.GetValue(this.ownerObject); }
set { this.fieldInfo.SetValue(this.ownerObject, value); }
}
}
// Our dummy class
public class MyClass
{
// Our field we want to expose.
private int myField;
public MyClass(int value)
{
this.myField = value;
}
// Just a function we use to print the content of myField.
public override string ToString()
{
return this.myField.ToString();
}
}
class Program
{
public static void Main()
{
// We create our class.
MyClass mc = new MyClass(5);
// We print field value, should be 5 :)
Console.WriteLine(mc.ToString());
// We create our field reference
FieldReference<int> fieldref = new FieldReference<int>(mc, "myField");
// We set the value using field reference.
// Note, we accessed a private field :)
fieldref.Value = 100;
// Now we print the value, should be 100!
Console.WriteLine(mc.ToString());
Console.ReadLine();
}
}
Looks like something that is better solved using delegates/events.
Instead of trying to do the impossible (force value types to behave as reference types), use an event and fire it whenever this value is changed.
Subscribe to this event from the caller/s and you are good to go.
Not knowing what you would want this for you could use a delegate for this, it does sound like a code smell though:
class myClass
{
Action<bool> modify;
public void method1(Action<bool> modify)
{
this.modify = modify;
}
public void ModifyIt()
{
modify(false);
}
}
bool b1 = true; //b1 is true
var m = new myClass();
m.method1(val => { b1 = val; });
m.ModifyIt(); //b1 is false now
This question will probably take a while to explain, and I'll need to provide background...
This is just something I'm playing about with and isn't for production, but at the moment I have some code which looks like this:
var myDataModel = new DataModel();
myDataModel.PropertyChanged += myDataModel_PropertyChanged;
myDataModel.ChangeProperty(t => t.TestValue, 2);
So, rather than using myDataModel.TestValue = 2 directly, I'm using a ChangeProperty extension method so that I can handle all of the change events and do anything I want to in one place. My extension method looks like this (and yes, I know it's hacky):
public static class NotifyPropertyChangedExtensions
{
public static void ChangeProperty<T, U>(
this T instance,
Expression<Func<T, U>> propertyToChange,
U newValue)
{
var member = propertyToChange.Body as MemberExpression;
if (member != null)
{
if (!propertyToChange.Compile().Invoke(instance).Equals(newValue))
{
var setProperty = instance.GetType().GetProperty(
member.Member.Name,
BindingFlags.SetProperty |
BindingFlags.Public |
BindingFlags.Instance);
if (setProperty != null)
{
// actually set the property
setProperty.SetValue(instance, newValue, null);
// raise the property changed event
if (typeof(INotifyPropertyChanged).IsAssignableFrom(
typeof(T)))
{
var delegatesToCall =
instance.GetType().GetField("PropertyChanged",
BindingFlags.Instance |
BindingFlags.NonPublic)
.GetValue(instance) as MulticastDelegate;
if (delegatesToCall != null)
{
var eventArgs = new PropertyChangedEventArgs(
setProperty.Name);
foreach (var #delegate in
delegatesToCall.GetInvocationList())
{
#delegate.Method.Invoke(
#delegate.Target,
new object[] { instance, eventArgs });
}
}
}
}
}
}
else
{
throw new ArgumentException(
string.Format(
"Cannot determine the property to change {0}",
propertyToChange));
}
}
}
With this architecture, my data model is quite clean:
public class DataModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int TestValue { get; set; }
}
That is, I can use auto-properties, and don't need to worry about raising events etc.
Now, what I actually want to do is something closer to this:
var dataModel = new DataModel();
myDataModel.PropertyChanged += myDataModel_PropertyChanged;
myDataModel.TestValue.Set(2); // this is what I want...
So, I'm thinking I'll basically need an extension method - but I can only see how to send the property itself (the TestValue in this case), and the new value. So then I wondered if it's possible, given a property, to find out the instance of the class it belongs to?
Don't do this. It breaks encapsulation.
No. In myDataModel.TestValue.Set(2); the extension method will always be called on the value returned by the property. There is no way to get the class, instance or property that returned the value.
You could do something like this:
var t = new DataModel();
((Expression<Func<int>>)(() => t.Foo)).Set(100);
with
static class Extensions
{
public static void Set<T>(this Expression<Func<T>> expression, T value)
{ ... }
}
but this is ugly, almost unreadable, unclear, inefficient, and error prone.
You're looking for Aspect Oriented Programming (AOP).
Have a look at PostSharp or LinFu.
There is no really clean solution to implementing INotifyPropertyChanged yet. If typing all the property setters is too much work or too error prone, I'd generate them with a T4 template.
Is it possible to get the property of a class from string and then set a value?
Example:
string s = "label1.text";
string value = "new value";
label1.text = value; <--and some code that makes this
How to do this?
Based this source, the equivalent of
shipment.<propName> = valueToUse,
where 'propName' is the name of the property provided as a string:
using System;
using System.Reflection;
namespace PropertyViaString
{
public class Shipment
{
public string Sender { get; set; }
}
class Program
{
static void Main(string[] args)
{
Shipment shipment = new Shipment();
SetValueExample(shipment, "Sender", "Popeye");
Console.WriteLine("Sender is {0}", shipment.Sender);
Console.ReadKey();
}
static void SetValueExample(Shipment shipment, string propName, string valueToUse)
{
Type type = shipment.GetType();
PropertyInfo senderProperty = type.GetProperty(propName);
senderProperty.SetValue(shipment, valueToUse, null);
}
}
}
prints
Sender is Popeye
You can use reflection to do this, but it will be quite slow?
Perhaps if you tell us what you're trying to achieve by doing this we can help, there are several patterns on event handlers etc. that usually makes this unnecessary.
The answer is use Reflection. However, there are many app frameworks that make the process much easier.
For example, have a look at Spring.Net Expressions. It allows you to do:
ExpressionEvaluator.SetValue(object, "label1", "text");
It is much more powerful and flexible than this simple example, so have a look.
If the given control is an instance variable on your form (if you used the built-in WinForms designer, most are), first get the control, and then set the property on it:
void Form_SetControlProperty(
String controlName, String propertyName, object value)
{
FieldInfo controlField = this.GetType().GetField(controlName,
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
object control = controlField.GetValue(this);
PropertyInfo property = control.GetType().GetProperty(propertyName);
property.SetValue(control, value, new object[0]);
}
You may need to tweak BindingFlags to get this to work.
This must be a method on your form. Call it as:
SetControlProperty("myLabel", "Text", "my label text");
Pay attention to the scope of the method. It any control within the form, but not the form itself (to access the form itself, set control to this).
Note that this uses reflection and will be slow and brittle (change the name of a control and it will break).
You need an instance of the object whose properties you want to set. From your example I'll pretend it is a label.
Label myLabel = new Label();
string s = "text";
string value = "new value";
System.Reflection.PropertyInfo[] properties = myLabel.GetType().GetProperties();
foreach (System.Reflection.PropertyInfo p in properties)
{
if(p.Name == s)
{
p.SetValue(myLabel, value, null);
}
}
I found this code:
Object someObject = myForm; <--- want to make this Object someObject = "myForm";
String propName = "Title";
System.Reflection.PropertyInfo pi = someObject.GetType().GetProperty(propName);
pi.SetValue(someObject, "New Value", new Object[0]);
It works. But what to do, that it would by possible to set someObject as a string.
Object someObject = (object)"myForm" <-- this doesn't work.
I want to create a method that changes enabled property. How do I pass the contorl name and property to a method.
If the following were my original method:
public void ChangeProperties()
{
btnAcesScore.Enabled = true;
}
I want to be able to change the "btnAcesScore" each time I call this method. How do I pass this to the method. I tried passing it as a string but that doesn't work.
Here is what I tried:
public void ChangeProperties(string category)
{
category = true;
}
ChangeProperties("btnAcesScore.Enabled");
Susan
Try this :
public void ChangeProperties(Control ctrl)
{
ctrl.Enabled = true;
}
and call it like that :
ChangeProperties(btnAcesScore);
What exactly is the purpose of this? Is it to reuse the method to arbitrarily change the Enabled property of any given control? If so, there is an easier way to accomplish it, as outlined by Canavar.
Or is the point of this method to toggle the setting? In which case, your method would look either like:
public void ChangeProperties()
{
btnAcesScore.Enabled = !btnAcesScore.Enabled;
}
or
public void ChangeProperties(Control ctrl)
{
ctrl.Enabled = !ctrl.Enabled;
}
depending on whether you wanted to hit just the one control, or provide access to many. In any event, I personally don't see much point to encapsulating a single property access within a method, and if you were insistent (and this method didn't adjust other properties), I'd at least rename it to something like ToggleEnabled.
Since the original question had a reflection tag I think she wanted a reflection answer (whether or not that is good design) so here is a Reflection answer.
the form has a controls collection and with this you can search for it and use reflection to set the property:
public void ChangeProperties(Form form, string category)
{
string[] parts = category.Split(".");
int index = form.Controls.IndexOfKey(parts[0]);
Control control = null;
if (index >= 0)
{
control = form.Controls[index].;
}
if (control != null)
{
PropertyInfo propertyInfo = control.GetType().GetProperty(parts[1]);
if (propertyInfo != null)
{
propertyInfo.SetValue(control, true);
}
}
}
if you call it from the form the control lives on
ChangeProperties(this, "btnAcesScore.Enabled");
How about also
void ChangeProperty(ref bool output)
{
output = true;
}
ChangeProperty(ref btnAcesScore.Enabled);
Not sure I totally understand your intent, but you could pass a delegate to some code that changed your property...
public void ChangeProperties(Action<bool> setprop)
{
...
setprop(true);
}
then call it:
ChangeProperties(b => btnAcesScore.Enabled = b);
I'd use reflection - use the GetType() Method on the object you send through to your method and then use the GetProperties to match against the property you send through. You can then set the values at that point.
Try this:
public void ChangeProperties(string category, object value)
{
var categoryConcat = category.Split('.');
var control = this.Controls.Cast<Control>()
.Where(x => x.Name == categoryConcat[0]).First();
control.GetType().GetProperty(categoryConcat[1])
.SetValue(control, value);
}
The example probably needs some checks on the existance of the control and the property.
Main()
{
ChangeProperties(ref category,True); //Where Category is the ID of the Textbox control i.e <asp:textbox ID="Category "></textbox>
}
public void ChangeProperties(ref TextBox category,bool val)
{
category.Enabled = val;
}