简体   繁体   English

Invalidate()自定义控件对每个属性的更改?

[英]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). 我正在开发一个自定义的winforms控件,该控件公开了许多影响控件外观的属性(背景,文本和悬停,单击以及图标等不同状态的不同颜色)。 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() . 对这些属性之一的更改使得必须重新绘制,因此目前每个属性都有一个getter和setter,该setter调用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() 缓存属性更改几毫秒,然后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() 使用某种反射来检测调用方是否要在下一行中更改另一个属性,如果是,则延迟对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 可能需要重绘的属性之前有一些属性,或者是所有此类属性的列表,这些属性在编译时已扩展到getter / setter

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. 请注意,我将远离选项2。关于选项1,以某种方式,属性更改已由系统缓存,只有UI线程返回到处理消息后,它才会重绘。 As for option 3, it seems a little to involved. 至于选项3,似乎有些牵连。

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. 然后使用bool,如果为true,则计时器的Tick处理程序将调用Invalidate()并将其设置回false。 Lastly make a method that you will use in place of Invalidate that will mark the bool to true. 最后,制作一个将代替Invalidate的方法,该方法会将布尔值标记为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. 您所要做的就是调用InvalidateIfNeeded()而不是Invalidate(),它应该可以工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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