Search code examples
c#anonymous-types

Change value for anonymous property of type string


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);

Solution

  • How about this. I'm a bit worried about the new ResetAfterTime() call. Don't know if the instance is around long enough. It might be collected by the Garbage Collector before the Timer fires. Would have to think about that but it seems to work fine.

    A Notifier class:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Text;
    
    namespace WpfApp1
    {
        public class PropertyNotifier : INotifyPropertyChanged
        {
            public void NotifyPropertyChanged(string name)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
            }
    
            // The view automatically fills the PropertyChanged event
            public event PropertyChangedEventHandler PropertyChanged;
        }
    }
    

    The Viewmodel:

    using System.ComponentModel;
    using System.Threading;
    
    namespace WpfApp1
    {
        public class ViewModel : PropertyNotifier
        {
            public ViewModel(string legend)
            {
                Legend = legend;
            }
    
            private string _Legend;
    
            /// <summary>
            /// Here's where the magic happens
            /// </summary>
            public string Legend
            {
                get => _Legend;
                set
                {
                    _Legend = value;
                    new ResetAfterTime<string>(this, () => Legend, value);
                }
            }
        }
    }
    

    And your enhanced routine:

    using System;
    using System.Linq.Expressions;
    using System.Reflection;
    using System.Threading;
    
    namespace WpfApp1
    {
        public class ResetAfterTime<T>
                where T : class
        {
            Timer _timer;
            PropertyInfo _propertyInfo;
            PropertyNotifier _notifier;
            int _due;
    
            public ResetAfterTime(PropertyNotifier notifier, Expression<Func<T>> property, T value, int due = 3000)
            {
                _notifier = notifier;
                _propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;
                _due = due;
    
                if (_propertyInfo == null)
                {
                    throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
                }
                else
                {
                    if (value != default)
                    {
                        StartTimer();
                    }
                }
            }
            private void StartTimer()
            {
                _timer = new Timer(MakeDisappear, null, _due, _due);
            }
    
            private void StopTimer()
            {
                _timer.Dispose();
                _timer = null;
            }
    
            private void MakeDisappear(object state)
            {
                SetValue(null);
                StopTimer();
            }
    
            private void SetValue(object value)
            {
                var t = _propertyInfo.GetType();
                _propertyInfo.SetValue(_notifier, value);
                _notifier.NotifyPropertyChanged(_propertyInfo.Name);
            }
        }
    }