ArcEngine无闪烁刷新
在ArcGIS二次开发中,不可避免地使用到地图控件MapControl的刷新,也许刷新操作只是一行代码的问题,但在实际项目的使用中,影响甚广:
- 刷新使用不当会造成地图不断闪烁,影响用户使用感;
- 数据量大时刷新使用不当会造成地图操作卡顿
以下根据这一年来的开发经验,总结了三种刷新方式:
1.完全刷新
若某个修改对地图控件的所有图层生效,可使用完全刷新,如修改地图控件的坐标系。
mapControl.ActiveView.Refresh();
2.局部刷新
由于直接Refresh会重载所有数据,效率低下,因此在开发过程中可以使用PartialRefresh局部刷新:
MapControl.ActiveView.PartialRefresh(esriViewDrawPhase phase, object Data, IEnvelope envelope);
参数中,data理论上可以指需要刷新的要素如Layer,Element,Geometry等,但是在使用的时候发现输入指定Layer其它图层其实也会被刷新,且在输入Element时会报错,个人认为,PartialRefresh的局部刷新主要还是通过刷新方式phase和刷新范围envelope来体现的,因此,在使用时,尽量精准确定这些参数,否则使用PartialRefresh与直接Refresh其实差别不大。以下详细介绍phase参数的意义:
public enum esriViewDrawPhase
{
// Draws nothing.
esriViewNone = 0,
// Draws the background.(背景,一般指图层)
esriViewBackground = 1,
// Draws the geography.(要素)
esriViewGeography = 2,
// Draws the selected geography.(选中要素)
esriViewGeoSelection = 4,
// Draws the annotation.(标注)
esriViewGraphics = 8,
// Draws the selected annotation.(选中的标注)
esriViewGraphicSelection = 16,
// Draws the foreground.(前景,一般指Element,标注等)
esriViewForeground = 32,
// View initialized: AfterDraw event only.
esriViewInitialized = 64,
// Draws everything.(所有要素)
esriViewAll = 255
}
日常开发过程中,常用到以下几种:
//刷新视图范围内的所有要素
MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewAll, null, envelope);
//刷新单个图层
MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, layer, envelope);
//刷新选中要素(只会刷新高亮的要素,如果之前有过去除部分要素的高亮效果的操作则不适用,否则之前的高亮效果依然会存在)
MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection, null, envelope);
//结合使用
MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeoSelection | esriViewDrawPhase.esriViewGeography,null, envelope);
//刷新前景,一般指Element,标注等,如在graphicsContainer.DeleteAllElements()之后,使用该方法可以避免图层闪烁
MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewForeground,null, envelope);
//刷新单个Element
mapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGraphics, element, element.Geometry.Envelope);
在使用过程中,一定要具体情况具体分析,灵活调用,如果能够尽可能地缩小所需要的的envelop范围,将会达到更好的无闪烁刷新效果。
3.无闪烁刷新
PartialRefresh在使用的时候虽然需要渲染的要素变少了,但是有时还是会有闪烁,以下介绍一种无闪烁的刷新方法——IViewRefresh。
public static void Refresh(AxMapControl mapControl,object data, IEnvelope env,esriViewDrawPhase type=esriViewDrawPhase.esriViewAll)
{
if (env == null)
env = mapControl.ActiveView.Extent;
if (data == null)
mapControl.ActiveView.PartialRefresh(type, data, env);
else
{
IViewRefresh viewRefresh = mapControl.Map as IViewRefresh;
viewRefresh.ProgressiveDrawing = true;
if (data.GetType().Name.Contains("List"))
{
dynamic temp = data as dynamic;
foreach (var layer in temp)
viewRefresh.RefreshItem((object)layer);
}
else
viewRefresh.RefreshItem(data);
}
}
以下分别是使用上述函数和使用PartialRefresh的效果:
(1) 使用上述Refresh函数
Refresh(MapControl,layer, MapControl.ActiveView.Extent);
(2)使用PartialRefresh,效果如下:
MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography | esriViewDrawPhase.esriViewGeoSelection, layer, MapControl.ActiveView.Extent);
使用无闪烁刷新的体验感明显有所提高。
4.MapControl比例尺变化时的渲染优化
在arcgis中,滚动鼠标时地图控件会经历比例尺的不断缩放,若操作频率过高,容易产生重影,即上一个比例尺还没渲染完就渲染下一个,数据量大话容易造成卡顿,可以加上如下操作,等比例尺固定后再渲染,省去中途无效的渲染:
MapControl.OnExtentUpdated += (s, p) =>
{
MapControl.Visible = false;
MapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewAll, null, MapControl.ActiveView.Extent);
MapControl.Visible = true;
};