Click here to Skip to main content
15,881,600 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi,
I'm working on an app written in WPF, the code is written in C#.
I have a question mark icon which when pressed suppose to set content to specific label.
The label content is binding to a property in the view model, lets call it 'NoneLegend'.
I want that property to clear itself after 5 second so I have a utility class that suppose to manage that. Inside that class I wrote an anonymous method that gets any type of property.
My question is how do I set that property to string.empty?
The method looks like this:
public static void EmptyStringAfterXseconds<T>(Expression<Func<T>> property)
        {
            var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
            if (propertyInfo == null)
            {
                throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
            }
            else
            {
                var t = propertyInfo.GetType();
                propertyInfo.SetValue(null, "");
            }
        }

And I'm calling it like that:
NoneLegend = "Bla bla...";
Utils.EmptyStringAfterXseconds(() => NoneLegend);


What I have tried:

..................................................................
Posted
Updated 8-Nov-20 23:44pm

You need an "object" to go along with your property info.

"Info" is meta data; the object (i.e. the "label") is the reference for getting / setting properties. "null" won't do it.

PropertyInfo.SetValue Method (System.Reflection) | Microsoft Docs[^]
 
Share this answer
 
If you can change the calling code, it would be simpler to pass an Action<T> to update the property value.

Otherwise, you'll need to extract the target instance from the expression. But be warned, this is quite fragile.
C#
public static class ExpressionExtensions
{
    private static object GetSourceObject(MemberExpression body)
    {
        if (body.Expression is ConstantExpression c)
        {
            return c.Value;
        }
        
        if (body.Expression is MemberExpression m && m.Expression is ConstantExpression mc)
        {
            if (m.Member is FieldInfo f) return f.GetValue(mc.Value);
            if (m.Member is PropertyInfo p) return p.GetValue(mc.Value);
        }
        
        throw new NotSupportedException("Invalid expression: " + body);
    }
    
    public static (object instance, PropertyInfo property) ExtractProperty(LambdaExpression expression)
    {
        if (expression is null) throw new ArgumentNullException(nameof(expression));
        
        if (expression.Body is MemberExpression body && body.Member is PropertyInfo property)
        {
            object instance = GetSourceObject(body);
            return (instance, property);
        }
        
        throw new NotSupportedException("Invalid expression: " + expression);
    }
}
C#
public static void SetPropertyAfterXseconds<T>(Expression<Func<T>> propertyToSet, T valueToSet = default)
{
    var (instance, property) = ExpressionExtensions.ExtractProperty(propertyToSet);
    property.SetValue(instance, valueToSet);
}
This will support two types of calls:
C#
public class Foo
{
    public string Bar { get; set; }
    
    public void DoIt()
    {
        // Option 1:
        SomeClass.SetPropertyAfterXseconds(() => Bar);
    }
}

// Option 2:
Foo x = new Foo { Bar = "Baz" };
SomeClass.SetPropertyAfterXseconds(() => x.Bar);
For option 1, the body expression will be a ConstantExpression pointing to this.

For option 2, the body expression will be a MemberExpression pointing to a field on a compiler-generated closure class.
 
Share this answer
 
v2
Comments
oronsultan 10-Nov-20 2:16am    
Hi Richard, Sorry for the late response.
Thank you very much for putting out so much effort in writing a detailed answer. This works fine!

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900