简体   繁体   中英

Invalidate() custom control on every property change?

I am working on a custom winforms control that exposes a lot of properties that affect how the control looks (different colors for background, text and for different states like hover, click as well as icons etc). A change to one of these properties makes a repaint necessary so at the moment every property has a getter and setter with the setter calling Invalidate() . This is extremely annoying to code and if multiple properties are changed at once, every single one of them causes a repaint even though one repaint at the end would be enough.

I had the following ideas but I don't know if they are possible or how to implement them:

  1. cache property changes for a few milliseconds and then Invalidate()
  2. use some kind of reflection to detect whether the caller is going to change another property in the next line and if so delay the call to Invalidate()
  3. maybe some Attributes before the properties that make a repaint necessary or a List of all such Properties that is expanded to the getters/setters at compile time

Can you give me some advice if these ideas make sense/are possible and point me to how to implement them?

Just a note, I would stay away from option 2. In regard to option 1, in a way the property changes are already being cached by the system, it will redraw only once the UI thread has gone back to processing messages. As for option 3, it seems a little to involved.

But in answer to your question, the easiest way to have this work is to create a timer in your class that fires off at a given interval. Then have a bool that if it is true the timer's Tick handler will call Invalidate() and set it back to false. Lastly make a method that you will use in place of Invalidate that will mark the bool to true.

There may be hazards that I am not aware of in your situation but here is an example:

public class InvalidationUserControl : UserControl
{
   bool _isInvalid = false;
   int _data;
   Timer t = new Timer();

   public InvalidationUserControl()
   {
      InitializeComponent();
      t.Interval = 100;  // Go ahead an play with this number, the higher
                         // it is the greater the latency
      t.Tick += t_Tick;
      t.Start();
   }

   void InvalidateIfNeeded()
   {
      _isInvalid = true;
   }

   void t_Tick(object sender, EventArgs e)
   {
      if (_isInvalid)
      {
          _isInvalid = false;
          Invalidate();
      }
   }

   public int Data
   {
       get { return _data; }
       set
       {
           _data = value;
           InvalidateIfNeeded();
       }
   }
}

There may be better ways out there but this is a quick solution that may work exactly the way you need it to.

All you have to do is call InvalidateIfNeeded() instead of Invalidate() and it should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM