ArcGIS Pro 3.4 二次开发 - Arcade

发布于:2025-05-22 ⋅ 阅读:(23) ⋅ 点赞:(0)

环境:ArcGIS Pro SDK 3.4 + .NET 8

Arcade

1 基本查询

1.1 基本查询

QueuedTask.Run(() =>
{
// 构建一个表达式
var query = @"Count($layer)"; // 计算 "layer" 中的要素数量
// 构建一个 CIMExpressionInfo
var arcade_expr = new CIMExpressionInfo()
{
Expression = query.ToString(),
// 返回类型可以是字符串、数字或默认值
// 当设置为默认值时,插件负责确定返回类型
ReturnType = ExpressionReturnType.Default
};
// 构建一个评估器
// 选择相关的配置文件 - 它必须支持 Pro 并且必须包含表达式中使用的任何配置文件变量
// 参考: https://developers.arcgis.com/arcade/profiles/
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
arcade_expr, ArcadeProfile.Popups))
{
// 为任何引用的配置文件变量提供值...
// 在我们的例子中是 '$layer'
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$layer", featLayer)
};
// 评估表达式
try
{
var result = arcade.Evaluate(variables).GetResult();
System.Diagnostics.Debug.WriteLine($"Result: {result.ToString()}");
}
// 处理任何异常
catch (InvalidProfileVariableException ipe)
{
// 指定的配置文件变量有问题
// TODO...
}
catch (EvaluationException ee)
{
// 查询评估有问题
// TODO...
}
}
});

1.2 使用要素进行基本查询

QueuedTask.Run(() =>
{
// 构建一个表达式
var query = @"$feature.AreaInAcres * 43560.0"; // 将英亩转换为平方英尺
// 构建一个 CIMExpressionInfo
var arcade_expr = new CIMExpressionInfo()
{
Expression = query.ToString(),
// 返回类型可以是字符串、数字或默认值
// 当设置为默认值时,插件负责确定返回类型
ReturnType = ExpressionReturnType.Default
};
// 构建一个评估器
// 选择相关的配置文件 - 它必须支持 Pro 并且必须包含表达式中使用的任何配置文件变量
// 参考: https://developers.arcgis.com/arcade/profiles/
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
arcade_expr, ArcadeProfile.Popups))
{
// 我们正在对所有要素评估表达式
using (var rc = featLayer.Search())
{
while (rc.MoveNext())
{
// 为引用的任何配置文件变量提供值...
// 在我们的例子中是 '$feature'
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$feature", rc.Current)
};
// 评估表达式(在这种情况下针对每个要素)
try
{
var result = arcade.Evaluate(variables).GetResult();
var val = ((double)result).ToString("0.0#");
System.Diagnostics.Debug.WriteLine(
$"{rc.Current.GetObjectID()} 面积: {val} 平方英尺");
}
// 处理任何异常
catch (InvalidProfileVariableException ipe)
{
// 指定的配置文件变量有问题
// TODO...
}
catch (EvaluationException ee)
{
// 查询评估有问题
// TODO...
}
}
}
}
});

1.3 使用 FeatureSetByName 检索要素

var map = MapView.Active.Map;
QueuedTask.Run(() =>
{
// 构建查询
var query = new StringBuilder();
var layer_name = "USA Current Wildfires - Current Incidents";
// 参考 https://developers.arcgis.com/arcade/function-reference/featureset_functions/
query.AppendLine(
$"var features = FeatureSetByName($map,'{layer_name}', ['*'], false);");
query.AppendLine("return Count(features);");
// 构建 CIMExpressionInfo
var arcade_expr = new CIMExpressionInfo()
{
Expression = query.ToString(),
// 返回类型可以是字符串、数字或默认值
// 当设置为默认值时,插件负责确定返回类型
ReturnType = ExpressionReturnType.Default
};
// 构建评估器
// 选择相关配置文件 - 它必须支持 Pro 并且必须包含表达式中使用的任何配置文件变量
// 参考:https://developers.arcgis.com/arcade/profiles/
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
arcade_expr, ArcadeProfile.Popups))
{
// 为任何引用的配置文件变量提供值...
// 在我们的例子中是 '$map'
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$map", map)
};
// 评估表达式
try
{
var result = arcade.Evaluate(variables).GetResult();
System.Diagnostics.Debug.WriteLine($"Result: {result.ToString()}");
}
// 处理任何异常
catch (InvalidProfileVariableException ipe)
{
// 指定的配置文件变量有问题
// TODO...
}
catch (EvaluationException ee)
{
// 查询评估有问题
// TODO...
}
}
});

1.4 使用过滤器检索要素

QueuedTask.Run(() =>
{
// 构建查询
var query = new StringBuilder();
// 参考 https://developers.arcgis.com/arcade/function-reference/featureset_functions/
query.AppendLine(
"var features = Filter($layer, 'DailyAcres is not NULL');");
query.AppendLine("return Count(features);");
// 构建 CIMExpressionInfo
var arcade_expr = new CIMExpressionInfo()
{
Expression = query.ToString(),
// 返回类型可以是字符串、数字或默认值
// 当设置为默认值时,插件负责确定返回类型
ReturnType = ExpressionReturnType.Default
};
// 构建评估器
// 选择相关配置文件 - 它必须支持 Pro 并且必须包含表达式中使用的任何配置文件变量
// 参考:https://developers.arcgis.com/arcade/profiles/
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
arcade_expr, ArcadeProfile.Popups))
{
// 为引用的任何配置文件变量提供值...
// 在我们的例子中是 '$layer'
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$layer", featLayer)
};
// 评估表达式
try
{
var result = arcade.Evaluate(variables).GetResult();
System.Diagnostics.Debug.WriteLine($"结果: {result.ToString()}");
}
// 处理任何异常
catch (InvalidProfileVariableException ipe)
{
// 指定的配置文件变量有问题
// TODO...
}
catch (EvaluationException ee)
{
// 查询评估有问题
// TODO...
}
}
});

1.5 使用数学函数计算基本统计量

QueuedTask.Run(() =>
{
// 构建查询
var query = new StringBuilder();
// 参考 https://developers.arcgis.com/arcade/function-reference/math_functions
query.AppendLine("var features = Filter($layer, 'DailyAcres is not NULL');"); // 过滤出 DailyAcres 不为空的要素
query.AppendLine("var count_feat = Count(features);"); // 计算要素数量
query.AppendLine("var sum_feat = Sum(features, 'DailyAcres');"); // 计算 DailyAcres 的总和
query.AppendLine("var max_feat = Max(features, 'DailyAcres');"); // 计算 DailyAcres 的最大值
query.AppendLine("var min_feat = Min(features, 'DailyAcres');"); // 计算 DailyAcres 的最小值
query.AppendLine("var avg_feat = Average(features, 'DailyAcres');"); // 计算 DailyAcres 的平均值
query.AppendLine("var answer = [count_feat, sum_feat, max_feat, min_feat, avg_feat]"); // 将结果存储在数组中
query.AppendLine("return Concatenate(answer,'|');"); // 将数组结果用 '|' 连接并返回
// 构建 CIMExpressionInfo
var arcade_expr = new CIMExpressionInfo()
{
Expression = query.ToString(),
// 返回类型可以是字符串、数字或默认值
// 当设置为默认值时,插件负责确定返回类型
ReturnType = ExpressionReturnType.Default
};
// 构建评估器
// 选择相关配置文件 - 它必须支持 Pro 并且必须包含表达式中使用的任何配置文件变量
// 参考: https://developers.arcgis.com/arcade/profiles/
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
arcade_expr, ArcadeProfile.Popups))
{
// 为引用的任何配置文件变量提供值...
// 在我们的例子中是 '$layer'
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$layer", featLayer)
};
// 评估表达式
try
{
var result = arcade.Evaluate(variables).GetResult();
System.Diagnostics.Debug.WriteLine($"Result: {result.ToString()}");
}
// 处理任何异常
catch (InvalidProfileVariableException ipe)
{
// 指定的配置文件变量有问题
// TODO...
}
catch (EvaluationException ee)
{
// 查询评估有问题
// TODO...
}
}
});

1.6 使用 FeatureSet 函数的 Filter 和 Intersects

var map = MapView.Active.Map;
QueuedTask.Run(() =>
{
// 构建查询
var query = new StringBuilder();
// https://developers.arcgis.com/arcade/function-reference/featureset_functions/
// 假设我们有两个图层 - 俄勒冈县(多边形)和犯罪(点)。犯罪数据来自 Pro SDK 社区示例数据。
// 选择相关县边界内的所有犯罪点并统计数量
query.AppendLine("var results = [];");
query.AppendLine("var counties = FeatureSetByName($map, 'Oregon_Counties', ['*'], true);");
// 'Clackamas','Multnomah','Washington'
query.AppendLine("var sel_counties = Filter(counties, 'DHS_Districts IN (2, 15, 16)');");
query.AppendLine("for(var county in sel_counties) {");
query.AppendLine("   var name = county.County_Name;");
query.AppendLine("   var cnt_crime = Count(Intersects($layer, Geometry(county)));");
query.AppendLine("   Insert(results, 0, cnt_crime);");
query.AppendLine("   Insert(results, 0, name);");
query.AppendLine("}");
query.AppendLine("return Concatenate(results,'|');");
// 构建 CIMExpressionInfo
var arcade_expr = new CIMExpressionInfo()
{
Expression = query.ToString(),
// 返回类型可以是字符串、数字或默认值
// 当设置为默认值时,插件负责确定返回类型
ReturnType = ExpressionReturnType.Default
};
// 构建评估器
// 选择相关配置文件 - 它必须支持 Pro 并且必须包含表达式中使用的任何配置文件变量。
// 参考:https://developers.arcgis.com/arcade/profiles/
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
arcade_expr, ArcadeProfile.Popups))
{
// 为引用的任何配置文件变量提供值...
// 在我们的例子中是 '$layer' 和 '$map'
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$layer", crimes_layer),
new KeyValuePair<string, object>("$map", map)
};
// 评估表达式
try
{
var result = arcade.Evaluate(variables).GetResult();
var results = result.ToString().Split('|', StringSplitOptions.None);
var entries = results.Length / 2;
int i = 0;
for (var e = 0; e < entries; e++)
{
var name = results[i++];
var count = results[i++];
System.Diagnostics.Debug.WriteLine($"'{name}' crime count: {count}");
}
}
// 处理任何异常
catch (InvalidProfileVariableException ipe)
{
// 指定的配置文件变量有问题
// TODO...
}
catch (EvaluationException ee)
{
// 查询评估有问题
// TODO...
}
}
});

2 评估表达式

2.1 评估 Arcade 标注表达式

var map = MapView.Active.Map;
QueuedTask.Run(() =>
{
// 假设我们有一个图层 - Oregon County (poly),它有一个 Arcade 标注表达式
// 我们想要交互式地评估这个表达式...
var def = oregon_cnts.GetDefinition() as CIMFeatureLayer;
// 获取标注类
var label_class = def.LabelClasses
.FirstOrDefault(lc => {
return lc.Name == "Arcade_Example_1" &&
lc.ExpressionEngine == LabelExpressionEngine.Arcade;
});
if (label_class == null)
return;
// 针对要素评估标注表达式
var expr_info = new CIMExpressionInfo()
{
Expression = label_class.Expression,
ReturnType = ExpressionReturnType.String
};
// https://developers.arcgis.com/arcade/profiles/labeling/
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
expr_info, ArcadeProfile.Labeling))
{
// 遍历要素
using (var rc = oregon_cnts.Search())
{
while (rc.MoveNext())
{
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$feature", rc.Current)
};
var result = arcade.Evaluate(variables).GetResult();
// 输出结果
System.Diagnostics.Debug.WriteLine(
$"[{rc.Current.GetObjectID()}]: {result}");
}
}
}
});

2.2 在渲染器上评估Arcade视觉变量表达式

var mv = MapView.Active;
var map = mv.Map;
QueuedTask.Run(() =>
{
// 假设我们有一个图层 - 俄勒冈县(多边形),它使用了我们想要交互式评估的视觉变量表达式...
var def = oregon_cnts.GetDefinition() as CIMFeatureLayer;
// 大多数要素渲染器都有一个VisualVariable集合
var renderer = def.Renderer as CIMUniqueValueRenderer;
var vis_variables = renderer.VisualVariables?.ToList() ??
new List<CIMVisualVariable>();
if (vis_variables.Count == 0)
return;// 如果没有视觉变量,直接返回
var vis_var_with_expr = new Dictionary<string, string>();
// 检查是否有使用表达式的视觉变量
foreach (var vv in vis_variables)
{
if (vv is CIMColorVisualVariable cvv)
{
if (!string.IsNullOrEmpty(cvv.ValueExpressionInfo?.Expression))
vis_var_with_expr.Add("Color", cvv.ValueExpressionInfo?.Expression);
}
else if (vv is CIMTransparencyVisualVariable tvv)
{
if (!string.IsNullOrEmpty(tvv.ValueExpressionInfo?.Expression))
vis_var_with_expr.Add("Transparency", tvv.ValueExpressionInfo?.Expression);
}
else if (vv is CIMSizeVisualVariable svv)
{
if (!string.IsNullOrEmpty(svv.ValueExpressionInfo?.Expression))
vis_var_with_expr.Add("Outline", svv.ValueExpressionInfo?.Expression);
}
}
if (vis_var_with_expr.Count == 0)
return;// 如果没有使用表达式的视觉变量,直接返回
// 遍历要素(外层)
// 对每个要素评估每个视觉变量...(内层)
// ...
// 另一种方式是遍历表达式(外层)
// 然后对每个要素评估表达式(内层)
using (var rc = oregon_cnts.Search())
{
while (rc.MoveNext())
{
foreach (var kvp in vis_var_with_expr)
{
var expr_info = new CIMExpressionInfo()
{
Expression = kvp.Value,
ReturnType = ExpressionReturnType.Default
};
// 对每个要素评估每个表达式...
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
expr_info, ArcadeProfile.Visualization))
{
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$feature", rc.Current)
};
// 注意2D地图也可以有视图比例...
// ...如果需要...
if (mv.ViewingMode == MapViewingMode.Map)
{
variables.Add(new KeyValuePair<string, object>(
"$view.scale", mv.Camera.Scale));
}
var result = arcade.Evaluate(variables).GetResult().ToString();
// 输出结果
System.Diagnostics.Debug.WriteLine(
$"[{rc.Current.GetObjectID()}] '{kvp.Key}': {result}");
}
}
}
}
foreach (var kvp in vis_var_with_expr)
{
  var expr_info = new CIMExpressionInfo()
  {
    Expression = kvp.Value,
    ReturnType = ExpressionReturnType.Default
  };
  using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
                                  expr_info, ArcadeProfile.Visualization))
  {
    // 遍历要素
    using (var rc = oregon_cnts.Search())
    {
      while (rc.MoveNext())
      {
        var variables = new List<KeyValuePair<string, object>>() {
          new KeyValuePair<string, object>("$feature", rc.Current)
        };
        var result = arcade.Evaluate(variables).GetResult();
        // 输出结果
        //...
      }
    }
  }
}
});

2.3 使用 Arcade 修改渲染器

var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(f => f.ShapeType == esriGeometryType.esriGeometryPolygon);
if (lyr == null) return;
QueuedTask.Run(() =>
{
// 从图层获取渲染器(假设它是唯一值渲染器)
var uvRenderer = lyr.GetRenderer() as CIMUniqueValueRenderer;
if (uvRenderer == null) return;
// 图层包含 STATE_NAME 字段
// 社区示例数据 Data\Admin\AdminSample.aprx
string expression = "if ($view.scale > 21000000) { return $feature.STATE_NAME } else { return 'All' }";
CIMExpressionInfo updatedExpressionInfo = new CIMExpressionInfo
{
Expression = expression,
Title = "Custom" // 可以是用于 UI 的任何字符串
};
// 设置渲染器的表达式
uvRenderer.ValueExpressionInfo = updatedExpressionInfo;
// 在图层上设置渲染器
lyr.SetRenderer(uvRenderer);
});

2.4 使用 Arcade 修改标签表达式

var lyr = MapView.Active.Map.GetLayersAsFlattenedList().OfType<FeatureLayer>().FirstOrDefault(f => f.ShapeType == esriGeometryType.esriGeometryPolygon);
if (lyr == null) return;
QueuedTask.Run(() =>
{
// 获取图层的定义
// 社区示例数据 Data\Admin\AdminSample.aprx
var lyrDefn = lyr.GetDefinition() as CIMFeatureLayer;
if (lyrDefn == null) return;
// 获取标签类 - 我们需要第一个
var listLabelClasses = lyrDefn.LabelClasses.ToList();
var theLabelClass = listLabelClasses.FirstOrDefault();
// 设置标签类的表达式以使用 Arcade 表达式
theLabelClass.Expression = "return $feature.STATE_NAME + TextFormatting.NewLine + $feature.POP2000;";
// 将标签定义设置回图层
lyr.SetDefinition(lyrDefn);
});

2.5 评估属性规则表达式

QueuedTask.Run(() =>
{
// 获取所需的要素类/表
var def = featLayer.GetFeatureClass().GetDefinition();
// 获取要评估表达式的属性规则
// AttributeRuleType.All, Calculation, Constraint, Validation
var validation_rule = def.GetAttributeRules(
AttributeRuleType.Validation).FirstOrDefault();
if (validation_rule == null)
return;
// 获取表达式
var expr = validation_rule.GetScriptExpression();
// 构造一个 CIMExpressionInfo
var arcade_expr = new CIMExpressionInfo()
{
Expression = expr,
// 返回类型可以是字符串、数字或默认值
ReturnType = ExpressionReturnType.Default
};
System.Diagnostics.Debug.WriteLine($"正在评估 {expr}:");
// 构造一个评估器
// 我们使用的是 ArcadeProfile.AttributeRules 配置文件...
// 参考: https://developers.arcgis.com/arcade/profiles/
using (var arcade = ArcadeScriptEngine.Instance.CreateEvaluator(
arcade_expr, ArcadeProfile.AttributeRuleValidation))
{
// 我们正在对所有要素评估表达式
using (var rc = featLayer.Search())
{
while (rc.MoveNext())
{
// 为引用的任何配置文件变量提供值...
// 在我们的例子中,我们假设是 '$feature'
// ...如果需要,使用 arcade.ProfileVariablesUsed()...
var variables = new List<KeyValuePair<string, object>>() {
new KeyValuePair<string, object>("$feature", rc.Current)
};
// 对每个要素评估表达式
try
{
var result = arcade.Evaluate(variables).GetResult();
// 'Validation' 属性规则返回 true 或 false...
var valid = System.Boolean.Parse(result.ToString());
System.Diagnostics.Debug.WriteLine(
$"{rc.Current.GetObjectID()} 有效: {valid}");
}
// 处理任何异常
catch (InvalidProfileVariableException ipe)
{
// 指定的配置文件变量有问题
// TODO...
}
catch (EvaluationException ee)
{
// 查询评估有问题
// TODO...
}
}
}
}
});

网站公告

今日签到

点亮在社区的每一天
去签到