views:

2206

answers:

6

I have my winform application gathering data using databinding. Everything looks fine except that I have to link the property with the textedit using a string:

Me.TextEdit4.DataBindings.Add(New System.Windows.Forms.Binding("EditValue", Me.MyClassBindingSource, "MyClassProperty", True))

This works fine but if I change the class' property name, the compiler obviously will not warn me .

I would like to be able to get the property name by reflection but I don't know how to specify the name of the property I want (I only know how to iterate among all the properties of the class)

Any idea?

+3  A: 

Ironically reflection expects that you provide property name to get it's info :)

You can create custom attribute, apply it to desired property. Then you will be able to simply get name of the property having this attribute.

aku
+1 for good use of custom Attributes!
Konrad Rudolph
A: 

You'll have the same problem using reflection because in order to find the right property in all the type's properties, you'll have to know its name, right?

Konrad Rudolph
A: 

You can reflect a Type, but you can't reflect its members except by name.

If that were the only property, or you knew for certain the ordering you could find it by index, but generally speaking a string is the safest way to go.

I believe changing the name will cause a run-time exception, but am not 100% certain, in either case that is probably the best possibility.

Assuming no exception occurs automatically, you could add a Debug.Assert that checks to see if the property by that name exists, but again that is run time only.

Guvante
A: 

1) Specify the exact property name that you want and keep it that way

2) Write a test involving that property name.

martinsb
+6  A: 

Here is an example of what I'm talking about:

[AttributeUsage(AttributeTargets.Property)]
class TextProperyAttribute: Attribute
{}

class MyTextBox
{
    [TextPropery]
    public string Text { get; set;}
    public int Foo { get; set;}
    public double Bar { get; set;}
}


static string GetTextProperty(Type type)
{
    foreach (PropertyInfo info in type.GetProperties())
    {
        if (info.GetCustomAttributes(typeof(TextProperyAttribute), true).Length > 0)
        {
            return info.Name;
        }
    }

    return null;
}

...

Type type = typeof (MyTextBox);

string name = GetTextProperty(type);

Console.WriteLine(name); // Prints "Text"
aku
Damn, you beat me to it … I was about to post an example. :-/
Konrad Rudolph
Textually almost the same, I might add.
Konrad Rudolph
Konrad Rudolph, today I lost ~200 rep for unknown reason, give me a chance :). Go upvote it!
aku
But if I understand correctly then I would need one class and one method for each property: FooPropertyAttribute and GetFooProperty, BarPropertyAttribute and GetBarAttribute. Is this correct?
MiguelE, no, you will need 1 attribute just to mark bindable property. If you need additional info, you can store it in that attribute.
aku
I still don't get it. Could you provide a sample about how to get all three class property names in the code sample (Text, Foo and Bar)?
MiguelE, maybe tomorrow, I'm a bit tired today.
aku
+6  A: 

If you are using C# 3.0, there is a way to get the name of the property dynamically, without hard coded it.

private string GetPropertyName<TValue>(Expression<Func<BindingSourceType, TValue>> propertySelector)
{
    var memberExpression = propertySelector.Body as MemberExpression;
    if (memberExpression != null)
    {
        return memberExpression.Member.Name;
    }
    else
    {
       return string.empty;    
    }
}

Where BindingSourceType is the class name of your datasource object instance.

Then, you could use a lambda expression to select the property you want to bind, in a strongly typed manner :

this.textBox.DataBindings.Add(GetPropertyName(o => o.MyClassProperty),
                              this.myDataSourceObject,
                              "Text");

It will allow you to refactor your code safely, without braking all your databinding stuff. But using expression trees is the same as using reflection, in terms of performance.

The previous code is quite ugly and unchecked, but you get the idea.

Romain Verdier
Nice, but it creates compilation dependency between UI and data source object.
aku
It should not be a problem... I'm not sure to see why the UI musn't know the type of objects it displays. In MVP/MVC, it is almost always the case, even if we use presentation model. But yes, if you can't know the type of the object, you can't use this solution.
Romain Verdier
I agree that strong typing is a nice things. However databinding usually relies on textual names. Usually you setup via some kind of GUI, or in config file (XAML for example). Though your solution is very cool!
aku
It seems that the need of the asker here is to keep in sync strings used to refer property names, and property names. He obviously knows what kind of object he binds :)
Romain Verdier
The VB compiler builds the lambda expression with an extra level so the VB equivalent needs to get a UnaryExpression from the propertySelector.Body then get the MemberExpression from the unary.Operand.
Jason Stangroome
Very nice solution. I still have to wrap my mind around lambda expressions but I see the beauty of this approach. Thumbs up!