在每次 属性 更改时使自定义控件无效?
Invalidate() custom control on every property change?
我正在开发一个自定义 winforms 控件,它公开了许多影响控件外观的属性(不同颜色的背景、文本和不同状态,如悬停、单击以及图标等)。更改其中一个属性需要重新绘制,因此目前每个 属性 都有一个 getter 和 setter,setter 调用 Invalidate()
。这对代码来说非常烦人,如果一次更改多个属性,即使最后一次重绘就足够了,每一个都会导致重绘。
我有以下想法,但我不知道它们是否可行或如何实现它们:
- 缓存属性变化几毫秒然后
Invalidate()
- 使用某种反射来检测调用者是否要在下一行中更改另一个 属性,如果是,则延迟对
Invalidate()
的调用
- 可能是在需要重绘的属性之前的一些属性,或者是在编译时扩展到 getters/setters 的所有此类属性的列表
如果这些想法使 sense/are 成为可能,你能给我一些建议并指出如何实施它们吗?
请注意,我会远离选项 2。关于选项 1,在某种程度上 属性 更改已被系统缓存,它只会在 UI 线程已返回处理消息。至于选项3,好像有点牵强。
但是为了回答您的问题,完成这项工作的最简单方法是在您的 class 中创建一个计时器,它会在给定的时间间隔内触发。然后有一个 bool,如果它是 true,定时器的 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(),它应该可以工作。
我正在开发一个自定义 winforms 控件,它公开了许多影响控件外观的属性(不同颜色的背景、文本和不同状态,如悬停、单击以及图标等)。更改其中一个属性需要重新绘制,因此目前每个 属性 都有一个 getter 和 setter,setter 调用 Invalidate()
。这对代码来说非常烦人,如果一次更改多个属性,即使最后一次重绘就足够了,每一个都会导致重绘。
我有以下想法,但我不知道它们是否可行或如何实现它们:
- 缓存属性变化几毫秒然后
Invalidate()
- 使用某种反射来检测调用者是否要在下一行中更改另一个 属性,如果是,则延迟对
Invalidate()
的调用
- 可能是在需要重绘的属性之前的一些属性,或者是在编译时扩展到 getters/setters 的所有此类属性的列表
如果这些想法使 sense/are 成为可能,你能给我一些建议并指出如何实施它们吗?
请注意,我会远离选项 2。关于选项 1,在某种程度上 属性 更改已被系统缓存,它只会在 UI 线程已返回处理消息。至于选项3,好像有点牵强。
但是为了回答您的问题,完成这项工作的最简单方法是在您的 class 中创建一个计时器,它会在给定的时间间隔内触发。然后有一个 bool,如果它是 true,定时器的 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(),它应该可以工作。