2015-03-31 36 views
0

我正在处理一个自定义winforms控件,该控件公开了很多影响控件外观的属性(不同颜色的背景,文本和不同的状态,如悬停,点击以及图标等)。对其中一个属性的更改会重新进行重绘,因此此时每个属性都有一个吸气器和吸气器,吸气器和吸气器呼叫Invalidate()。这对代码来说非常烦人,如果多个属性同时被更改,它们中的每一个都会导致重新绘制,即使重新绘制一次就足够了。对每个属性更改都无效()自定义控件?

我有以下想法,但我不知道他们是否是可能的,或者如何实现它们:

  1. 几毫秒的高速缓存属性更改,然后Invalidate()
  2. 使用某种反射到检测呼叫者是否要更换下一行中的另一个属性,如果是这样,则将呼叫延迟到Invalidate()
  3. 可能需要重绘属性之前的某些属性或所有此类属性的列表展开为getters /编译器在编译时

如果这些想法有意义/可能,并指出如何实施它们,您能给我一些建议吗?

+0

_if一次更改多个属性,_ ??你的意思是代码而不是用户?为此可以使用Suspend/ResumeLayout,否? – TaW 2015-04-01 06:42:41

+0

@TaW是的我的意思是代码。我不知道挂起/ resumelayout,我会研究它。谢谢 ! – user1950929 2015-04-01 07:11:36

回答

0

只是一个说明,我会远离选项2.关于选项1,以属性更改已被系统缓存的方式,它只会在UI线程返回处理消息后重绘。至于方案3,似乎有点牵扯。

但是在回答你的问题时,最简单的方法就是在你的班级中创建一个计时器,该计时器在给定的时间间隔内启动。然后有一个布尔,如果它是真的计时器的Tick处理程序将调用Invalidate()并将其设置为false。最后制作一个你将用来代替Invalidate的方法,它将bool标记为true。

有可能是我不知道在你的情况的危害,但这里有一个例子:

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

可能有更好的办法在那里,但,这是一个快速的解决方案,它可以工作必须是您需要它。

所有你需要做的就是调用InvalidateIfNeeded()而不是Invalidate(),它应该工作。

+0

谢谢,我会试试这个 – user1950929 2015-04-01 07:37:54

+0

当在设计器中删除控件时,这可能会导致竞争条件。 – 2017-01-10 15:31:59