如何用内部Timer重绘GMapMarker实现500ms间隔闪烁效果
解决GMap.NET标记图片可控闪烁的问题
我明白你的痛点——用GMapControl.Invalidate()会重绘整个地图,导致闪烁不受控,而且地图闲置时OnRedraw()还不触发。其实关键是只重绘标记自身的区域,而不是整个地图,同时要处理Timer的线程问题。下面给你一步步解决:
核心思路
- 用WinForms的
System.Windows.Forms.Timer替代System.Timers.Timer,避免跨线程UI操作的问题(WinForms Timer的Tick事件本身就在UI线程触发)。 - 给标记添加一个状态字段(比如控制显示/隐藏或透明度),用来实现闪烁效果。
- 在Timer事件中切换状态,然后只刷新标记所在的屏幕区域,而不是整个地图控件。
修改后的完整代码
namespace GMap.NET.WindowsForms.Markers { public class GMarkerNode : GMapMarker { public Image Image { get; set; } private System.Windows.Forms.Timer _flashTimer; // 控制闪烁的状态字段,这里用显示/隐藏示例,也可以用透明度 private bool _isMarkerVisible = true; public GMarkerNode(PointLatLng p) : base(p) { // 使用WinForms Timer,Tick事件在UI线程触发 _flashTimer = new System.Windows.Forms.Timer() { Interval = 500, Enabled = true }; _flashTimer.Tick += FlashTimer_Tick; } private void FlashTimer_Tick(object sender, EventArgs e) { // 切换闪烁状态 _isMarkerVisible = !_isMarkerVisible; // 计算标记在屏幕上的矩形区域 var markerScreenRect = new Rectangle( LocalPosition.X, LocalPosition.Y, Image?.Width ?? 0, Image?.Height ?? 0); // 只刷新这个区域,而不是整个地图 MapControl?.Invalidate(markerScreenRect); } public override void OnRender(Graphics g) { if (Image != null && _isMarkerVisible) { g.DrawImage(Image, LocalPosition); } // 如果要做透明度闪烁,可以用下面的代码替代上面的判断 // if (Image != null) // { // var alpha = _isMarkerVisible ? 255 : 100; // using (var attr = new ImageAttributes()) // { // var matrix = new ColorMatrix(); // matrix.Matrix33 = alpha / 255f; // attr.SetColorMatrix(matrix); // g.DrawImage(Image, new Rectangle(LocalPosition, Image.Size), 0, 0, Image.Width, Image.Height, GraphicsUnit.Pixel, attr); // } // } } public override void Dispose() { _flashTimer?.Stop(); _flashTimer?.Dispose(); Image?.Dispose(); base.Dispose(); } } }
关键细节解释
- 为什么用WinForms Timer?:
System.Timers.Timer的Elapsed事件是在后台线程触发的,直接操作UI控件会引发跨线程异常,而WinForms Timer的Tick事件天然在UI线程执行,省去了Invoke的麻烦。 - 只刷新标记区域:通过
MapControl.Invalidate(markerScreenRect),只告诉控件重绘标记所在的一小块矩形,不会触发整个地图的OnRedraw(),完美解决地图闲置时的问题,也避免了不必要的性能消耗。 - 闪烁效果扩展:代码里提供了两种闪烁方式——显示/隐藏,或者透明度变化,你可以根据需求选择。
这样修改后,你的标记就会每500ms稳定闪烁,而且不会影响整个地图的重绘啦!
内容的提问来源于stack exchange,提问作者Matej Krhin
相关产品推荐
相关产品推荐

