Common

WPF UIUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
public class UiUtils
{
private static DispatcherOperationCallback
exitFrameCallback = new DispatcherOperationCallback(ExitFrame);
/// <summary>
/// 刷新界面
/// </summary>
public static void DoEvents()
{
DispatcherFrame nestedFrame = new DispatcherFrame();
DispatcherOperation exitOperation =
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Background,
exitFrameCallback, nestedFrame);
Dispatcher.PushFrame(nestedFrame);

if (exitOperation.Status != DispatcherOperationStatus.Completed)
{
exitOperation.Abort();
}
}
/// <summary>
/// 调用UI线程执行
/// </summary>
/// <param name="action">等待执行方法</param>
public static void Invoke(Action action)
{
System.Windows.Application.Current.Dispatcher.Invoke(action);
}
/// <summary>
/// 获取窗体所在屏幕
/// </summary>
/// <param name="window">窗体</param>
/// <returns>屏幕</returns>
public static Screen GetScreen(Window window)
{
PresentationSource source = PresentationSource.FromVisual(window);
Visual visual = source.RootVisual;
var screen = System.Windows.Forms.Screen.FromHandle(new WindowInteropHelper(window).Handle);
return screen;
}
/// <summary>
/// 获取窗体所在屏幕工作区(不包含任务栏)大小
/// </summary>
/// <param name="window">窗体</param>
/// <returns>工作区大小</returns>
public static Rect GetScreenWorkingAreaRect(Window window)
{
var scale = PresentationSource.FromVisual(window).CompositionTarget.TransformToDevice.M11;
Screen screen = GetScreen(window);
Rect rect = new Rect(0, 0, screen.WorkingArea.Width / scale, screen.WorkingArea.Height / scale);
return rect;
}
/// <summary>
/// 最大化窗体
/// </summary>
/// <param name="window">窗体</param>
public static void MaximizeWindow(Window window)
{
if (window.WindowState == WindowState.Maximized)
{
window.WindowState = WindowState.Normal;
//var bitmap = new BitmapImage(new Uri("pack://application:,,,/Shexo;component/res/PNG_Maximize_ZoomIn.png"));
//image.Source = bitmap;
}
else
{
Rect rect = UiUtils.GetScreenWorkingAreaRect(window);
window.MaxHeight = rect.Height;
window.WindowState = WindowState.Maximized;
//var bitmap = new BitmapImage(new Uri("pack://application:,,,/Shexo;component/res/PNG_Maximize_ZoomOut.png"));
//image.Source = bitmap;
}
}
/// <summary>
/// 窗体居中于工作区
/// </summary>
/// <param name="window">窗体</param>
public static void Centralize(Window window)
{
Rect rect = GetScreenWorkingAreaRect(window);
window.Left = (rect.Width - window.Width) / 2;
window.Top = (rect.Height - window.Height) / 2;
}
/// <summary>
/// 窗体居中于拥有者
/// </summary>
/// <param name="window">窗体</param>
public static void CentralizeOwner(Window window)
{
Window owner = window.Owner;
Rect rect = new Rect(owner.Left, owner.Top, owner.Width, owner.Height);
window.Left = (rect.Width - window.Width) / 2 + owner.Left;
window.Top = (rect.Height - window.Height) / 2 + owner.Top;
}
/// <summary>
/// 注册窗体拖动事件
/// </summary>
/// <param name="frameworkElement">窗体控件</param>
public static void RegisterWindowMoveEvent(FrameworkElement frameworkElement)
{
frameworkElement.PreviewMouseMove += MoveWindow_PreviewMouseMove;
}

private static object ExitFrame(object state)
{
DispatcherFrame frame = state as DispatcherFrame;
frame.Continue = false;
return null;
}
private static void MoveWindow_PreviewMouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (Mouse.LeftButton != MouseButtonState.Pressed)
return;
FrameworkElement frameworkElement = sender as FrameworkElement;
DependencyObject parent = VisualTreeHelper.GetParent(frameworkElement);
while (parent != null && !(parent is Window))
parent = VisualTreeHelper.GetParent(parent);
if (parent == null)
return;
Window window = parent as Window;

window.DragMove();
}
}

FileUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
public class FileUtils
{
/// <summary>
/// 读取文本文件内容
/// </summary>
/// <param name="filePath">文本文件路径</param>
/// <returns>文本文件内容</returns>
public static string Read(string filePath)
{
StreamReader sr = null;
string readText = string.Empty;
try
{
sr = new StreamReader(filePath);
readText = sr.ReadToEnd();
}
catch (Exception ex)
{
LogUtils.AppLog("读取文本文件内容失败!", Enum.LogLevel.Warning, ex);
}
finally { if (sr != null) try { sr.Close(); } catch { } }
return readText;
}
/// <summary>
/// 写入文本文件内容
/// </summary>
/// <param name="filePath">文本文件路径</param>
/// <param name="filePath">写入内容</param>
/// <returns>写入结果</returns>
public static bool Write(string filePath, string text)
{
StreamWriter sw = null;
try
{
sw = new StreamWriter(filePath);
sw.Write(text);
sw.Flush();
return true;
}
catch(Exception ex)
{
LogUtils.AppLog("写入文本文件内容失败!", Enum.LogLevel.Warning, ex);
return false;
}
finally { if (sw != null) try { sw.Close(); } catch { } }
}
/// <summary>
/// 追加文本文件内容
/// </summary>
/// <param name="filePath">文本文件路径</param>
/// <param name="filePath">追加内容</param>
/// <returns>追加结果</returns>
public static bool Append(string txtFilePath, string content)
{
FileStream fileStream = null;
StreamWriter streamWriter = null;
try
{
if (File.Exists(txtFilePath))
{
streamWriter = File.AppendText(txtFilePath);
}
else
{
fileStream = new FileStream(txtFilePath, FileMode.OpenOrCreate);
streamWriter = new StreamWriter(fileStream);
}
streamWriter.Write(content);
streamWriter.Flush();
return true;
}
catch (Exception ex)
{
LogUtils.AppLog("写入文本文件内容失败!", Enum.LogLevel.Warning, ex);
return false;
}
finally
{
if (streamWriter != null)
{
streamWriter.Close();
}
if (fileStream != null)
{
fileStream.Close();
}
}
}
}

TextBoxUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
public class TextBoxUtils
{
/// <summary>
/// 设置TextBox输入必须为小数
/// </summary>
/// <param name="textBox">TextBox控件</param>
public static void SetInputMustDecimal(TextBox textBox)
{
InputMethod.SetIsInputMethodEnabled(textBox, false);
textBox.PreviewTextInput += (object sender, TextCompositionEventArgs e) =>
{
TextBox textBox = sender as TextBox;
if (textBox == null)
return;
if (e.Text == ".")
{
if (textBox.Text.Length == 0 || textBox.Text.Contains("."))
e.Handled = true;
}
else
{
bool rst = int.TryParse(e.Text, out int i);
e.Handled = !rst;
}
};
textBox.TextChanged += (object sender, TextChangedEventArgs e) =>
{
TextBox textBox = sender as TextBox;
if (textBox == null)
return;
bool rst = double.TryParse(textBox.Text, out double d);
if (!rst)
{
if (e.Changes.Count < 1)
return;
int offset = e.Changes.ElementAt(0).Offset;
textBox.Text = textBox.Text.Remove(offset);
}
};
}
/// <summary>
/// 设置TextBox输入必须为整数
/// </summary>
/// <param name="textBox">TextBox控件</param>
public static void SetInputMustInt(TextBox textBox)
{
InputMethod.SetIsInputMethodEnabled(textBox, false);
textBox.PreviewTextInput += (object sender, TextCompositionEventArgs e) =>
{
TextBox textBox = sender as TextBox;
if (textBox == null)
return;
bool rst = int.TryParse(e.Text, out int i);
e.Handled = !rst;
};
textBox.TextChanged += (object sender, TextChangedEventArgs e) =>
{
TextBox textBox = sender as TextBox;
if (textBox == null)
return;
bool rst = int.TryParse(textBox.Text, out int i);
if (!rst)
{
if (e.Changes.Count < 1)
return;
int offset = e.Changes.ElementAt(0).Offset;
textBox.Text = textBox.Text.Remove(offset);
}
};
}
}

DataTableUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
public class DataTableUtils
{
public static DataTable FromCSV(string csvFilePath, string separator = ",")
{
DataTable dt = new DataTable();
FileStream fs = new FileStream(csvFilePath, FileMode.Open, FileAccess.Read);
StreamReader sr = new StreamReader(fs, Encoding.UTF8);
try
{
string strLine = null;
string[] arrayLine = null;
bool isFirst = true;
while (!string.IsNullOrEmpty(strLine = sr.ReadLine()))
{
strLine = strLine.Trim();
arrayLine = strLine.Split(separator);
int dtColumns = arrayLine.Length;
if (isFirst)
{
for (int i = 0; i < dtColumns; i++)
{
dt.Columns.Add(arrayLine[i]);
}
isFirst = false;
}
else
{
DataRow dataRow = dt.NewRow();//新建一行
for (int j = 0; j < dtColumns; j++)
{
dataRow[j] = arrayLine[j].Trim('\"');
}
dt.Rows.Add(dataRow);
}
}
}
catch (Exception ex)
{
LogUtils.AppLog("读取csv文件失败!", Enum.LogLevel.Error, ex);
}
finally
{
if (sr != null) try { sr.Close(); } catch { }
if (fs != null) try { fs.Close(); } catch { }
}
return dt;
}
public static void ToCSV(string csvFilePath, DataTable dt)
{
FileStream fs = null;
StreamWriter sw = null;
string data = null;
try
{
if (File.Exists(csvFilePath))
{
System.Windows.MessageBoxResult messageBoxResult = ProMessageUtils.ShowDialog(
"文件已经存在,是否覆盖?\r\n【是】- 覆盖并接入内容;\r\n" +
"【否】- 不覆盖,追加内容;\r\n【取消】- 退出。", "提示",
System.Windows.MessageBoxButton.YesNoCancel, System.Windows.MessageBoxImage.Question);
if (messageBoxResult == System.Windows.MessageBoxResult.Yes)
{
fs = new FileStream(csvFilePath, FileMode.Create, FileAccess.Write);
sw = new StreamWriter(fs, Encoding.UTF8);
//写出列名称
for (int i = 0; i < dt.Columns.Count; i++)
{
data += dt.Columns[i].ColumnName.ToString();
if (i < dt.Columns.Count - 1)
{
data += ",";//中间用,隔开
}
}
sw.WriteLine(data);
}
else if (messageBoxResult == System.Windows.MessageBoxResult.No)
{
fs = new FileStream(csvFilePath, FileMode.Append, FileAccess.Write);
sw = new StreamWriter(fs, Encoding.UTF8);
}
}
for (int i = 0; i < dt.Rows.Count; i++)
{
data = null;
for (int j = 0; j < dt.Columns.Count; j++)
{
data += dt.Rows[i][j].ToString();
if (j < dt.Columns.Count - 1)
{
data += ",";//中间用,隔开
}
}
sw.WriteLine(data);
}
}
catch(Exception ex)
{
LogUtils.AppLog("写入csv文件失败!", Enum.LogLevel.Error, ex);
}
finally
{
if (sw != null) try { sw.Close(); } catch { }
if (fs != null) try { fs.Close(); } catch { }
}
}
public static DataTable FromExcel(string excelFilePath, string sheetName)
{
DataTable dataTable = new DataTable();
string extension = Path.GetExtension(excelFilePath);
IWorkbook wb = null;
using (FileStream fs = File.Open(excelFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
try
{
if (extension == ".xlsx" || extension == "xlsx")
wb = new XSSFWorkbook(fs);
else if (extension == ".xls" || extension == "xls")
wb = new HSSFWorkbook(fs);
else
{
ProMessageUtils.ShowDialog($"错误文件类型{extension}!");
return dataTable;
}
}
catch (Exception ex)
{
LogUtils.AppLog("读取Excel文件失败!", Enum.LogLevel.Error, ex);
}
finally { if(fs!=null) try { fs.Close(); } catch { } }
}
ISheet ws = wb.GetSheet(sheetName);

int rowNum = ws.LastRowNum ;//总行数-1 起始为0
int colNum = ws.GetRow(0).LastCellNum;
for (int i = 0; i < colNum; i++)
{
ICell cell = ws.GetRow(0)?.GetCell(i);
string val = cell?.StringCellValue;
if (val != null)
dataTable.Columns.Add(val);
}
if (rowNum > 1)
{
for (int i = 1; i < rowNum; i++)
{
DataRow dataRow = dataTable.NewRow();
for (int j = 0; j < colNum; j++)
{
IRow row = ws.GetRow(i);
ICell cell = row.GetCell(j);
dataRow[j] = GetValue(cell);
}
dataTable.Rows.Add(dataRow);
}
}
return dataTable;
}
public static void ToExcel(string excelFilePath, DataTable dataTable)
{
string extension = Path.GetExtension(excelFilePath);
IWorkbook wb = null;
using (FileStream fs = File.Open(excelFilePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
{
try
{
if (extension == "xlsx")
wb = new XSSFWorkbook(fs);
else if (extension == "xls")
wb = new HSSFWorkbook(fs);
else
{
ProMessageUtils.ShowDialog($"错误文件类型{extension}!");
return;
}
}
catch (Exception ex)
{
LogUtils.AppLog("读取Excel文件失败!", Enum.LogLevel.Error, ex);
}
finally { if (fs != null) try { fs.Close(); } catch { } }
}
ISheet ws = wb.CreateSheet();
IRow firstrow = ws.CreateRow(0);
for (int c = 0; c <= dataTable.Columns.Count - 1; c++)
firstrow.CreateCell(c).SetCellValue(dataTable.Columns[c].ColumnName);
for (int i = 1; i <= dataTable.Rows.Count - 1; i++)
{
IRow dataRow = ws.CreateRow(i);
for (int j = 0; j <= dataTable.Columns.Count - 1; j++)
{
ICell cell = dataRow.CreateCell(j);
cell.SetCellValue(dataTable.Rows[i][j]?.ToString());
}
}
using (FileStream fs = File.OpenWrite(excelFilePath))
{
try
{
wb.Write(fs, false);
}
catch(Exception ex)
{
LogUtils.AppLog("写入Excel失败!", Enum.LogLevel.Error, ex);
}
finally { if (fs != null) try { fs.Close(); } catch { } }
}
}

static object GetValue(ICell cell)
{
if (cell == null)
return null;
switch (cell.CellType)
{
case CellType.Blank: //BLANK:
return null;
case CellType.Boolean: //BOOLEAN:
return cell.BooleanCellValue;
case CellType.Numeric: //NUMERIC:
return cell.NumericCellValue;
case CellType.String: //STRING:
return cell.StringCellValue;
case CellType.Error: //ERROR:
return cell.ErrorCellValue;
case CellType.Formula: //FORMULA:
default:
return "=" + cell.CellFormula;
}
}
}

EncryptionUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
public class EncryptionUtils
{
static string _AES_SECRET_KEY = "9FCA07E9-06FB-465E-AF42-558CB1A2F3E3";
// 加密字符串
public static string AesEncrypt(string plaintext)
{
// 将密钥转换为字节数组
byte[] keyBytes = Encoding.UTF8.GetBytes(_AES_SECRET_KEY);
using (Aes aes = Aes.Create())
{
aes.Key = keyBytes;
aes.GenerateIV();
// 创建加密器
ICryptoTransform encryptor = aes.CreateEncryptor();
// 将明文转换为字节数组
byte[] plaintextBytes = Encoding.UTF8.GetBytes(plaintext);
// 加密明文
byte[] ciphertextBytes = encryptor.TransformFinalBlock(plaintextBytes, 0, plaintextBytes.Length);
// 将密文和IV合并
byte[] combinedBytes = new byte[aes.IV.Length + ciphertextBytes.Length];
Array.Copy(aes.IV, 0, combinedBytes, 0, aes.IV.Length);
Array.Copy(ciphertextBytes, 0, combinedBytes, aes.IV.Length, ciphertextBytes.Length);
// 返回Base64编码的密文
return Convert.ToBase64String(combinedBytes);
}
}

// 解密字符串
public static string AesDecrypt(string ciphertext)
{
// 将密钥转换为字节数组
byte[] keyBytes = Encoding.UTF8.GetBytes(_AES_SECRET_KEY);
// 将Base64编码的密文转换为字节数组
byte[] combinedBytes = Convert.FromBase64String(ciphertext);
// 从密文中分离出IV和加密后的数据
byte[] ivBytes = new byte[16];
byte[] ciphertextBytes = new byte[combinedBytes.Length - ivBytes.Length];
Array.Copy(combinedBytes, ivBytes, ivBytes.Length);
Array.Copy(combinedBytes, ivBytes.Length, ciphertextBytes, 0, ciphertextBytes.Length);
using (Aes aes = Aes.Create())
{
aes.Key = keyBytes;
aes.IV = ivBytes;
// 创建解密器
ICryptoTransform decryptor = aes.CreateDecryptor();
// 解密密文
byte[] plaintextBytes = decryptor.TransformFinalBlock(ciphertextBytes, 0, ciphertextBytes.Length);
// 将明文转换为字符串并返回
return Encoding.UTF8.GetString(plaintextBytes);
}
}
}

GIS

SheetDesignationUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
public class SheetDesignationUtils
{
private static char[] LatCharArray = {'A','B','C','D','E','F','G','H','I','J','K'
,'L','M','N','O','P','Q','R','S','T','U','V'};
private static char[] ScaleCharArray = { 'A', 'B', 'C', 'R', 'D', 'E', 'F', 'G', 'H' };
private static double[] LatDArray = { 14400, 7200, 3600, 2400, 1200, 600, 300, 150, 75 };
private static double[] LonDArray = { 21600, 10800, 5400, 3600, 1800, 900, 450, 225, 112.5 };

/// <summary>
/// 获取图幅编号
/// </summary>
/// <param name="lon">经度/秒</param>
/// <param name="lat">纬度/秒</param>
/// <param name="scale">比例尺</param>
/// <returns>图幅号</returns>
public static string GetSheetNo(int lon, int lat, SheetScale scale)
{
//*|*|**|*|***|***
if (lat < -(88 * 60 * 60) || lat > 88 * 60 * 60)
throw new Exception("纬度不正确,请检查!");
if (lon < 0 || lon > 180 * 60 * 60)
throw new Exception("经度不正确,请检查!");
string numString = "";
numString += GetMillionRowID(lat);
numString += GetMillionColumnID(lon);
if (scale == SheetScale._1000000)
return numString;
numString += GetScaleID(scale);
numString += GetRowID(lat, scale);
numString += GetColumnID(lon, scale);
return numString;
}

/// <summary>
/// 获取百万比例尺行号
/// </summary>
/// <param name="lat">纬度/秒</param>
/// <returns>百万比例尺行号</returns>
public static char GetMillionRowID(int lat)
{
int a = lat / (4 * 3600);
return LatCharArray[a];
}

/// <summary>
/// 获取百万比例尺列号
/// </summary>
/// <param name="lon">经度/秒</param>
/// <returns>百万比例尺列号</returns>
public static int GetMillionColumnID(int lon)
{
int b = lon / (6 * 3600) + 31;
return b;
}

/// <summary>
/// 获取比例尺代号
/// </summary>
/// <param name="scale">比例尺</param>
/// <returns>比例尺代号</returns>
public static char GetScaleID(SheetScale scale)
{
int scaleIndex = Convert.ToInt32(scale);
char scaleId = ScaleCharArray[scaleIndex];
return scaleId;
}

/// <summary>
/// 获取当前比例尺行号
/// </summary>
/// <param name="lat">纬度/秒</param>
/// <param name="scale">比例尺</param>
/// <returns>当前比例尺行号</returns>
public static string GetRowID(int lat, SheetScale scale)
{
int scaleIndex = Convert.ToInt32(scale);
int c = Convert.ToInt32(4 * 3600 / LatDArray[scaleIndex]) -
Convert.ToInt32(lat % (4 * 3600) / LatDArray[scaleIndex]);
return c.ToString().PadRight(3, '0');
}

/// <summary>
/// 获取当前比例尺列号
/// </summary>
/// <param name="lon">经度/秒</param>
/// <param name="scale">比例尺</param>
/// <returns>当前比例尺列号</returns>
public static string GetColumnID(int lon, SheetScale scale)
{
int scaleIndex = Convert.ToInt32(scale);
int d = Convert.ToInt32(lon % (6 * 3600) / LonDArray[scaleIndex]) + 1;
return d.ToString().PadRight(3, '0');
}

/// <summary>
/// 根据图幅号获取经纬度范围(北半球)
/// </summary>
/// <param name="frmNo">图幅号</param>
/// <returns>图幅范围</returns>
/// <exception cref="Exception">图幅号错误异常</exception>
public static SheetArea GetSheetArea(string frmNo)
{
if (frmNo.Length != 10)
throw new Exception("图幅号错误,请输入标准十位图幅编号!");
int latMillionNum, lonMillionNum, latNum, lonNum, scaleNum;
char latMillionChar, scaleChar;

latMillionChar = char.Parse(frmNo.Substring(0, 1));
latMillionNum = LatCharArray.ToList().IndexOf(latMillionChar);
if (latMillionNum == -1)
throw new Exception("图幅号错误,请检查百万比例尺纬度号!");

scaleChar = char.Parse(frmNo.Substring(3, 1));
scaleNum = ScaleCharArray.ToList().IndexOf(scaleChar);
if (scaleNum == -1)
throw new Exception("图符号错误,请检查比例尺代号!");

if (!int.TryParse(frmNo.Substring(1, 2), out lonMillionNum))
throw new Exception("图幅号错误,请检查百万比例尺经度号!");
if (!int.TryParse(frmNo.Substring(4, 3), out latNum))
throw new Exception("图幅号错误,请检查纬度号!");
if (!int.TryParse(frmNo.Substring(7, 3), out lonNum))
throw new Exception("图幅号错误,请检查经度号!");
SheetArea sheetArea = new SheetArea();
sheetArea.LatMin = latMillionNum * 4 * 3600 + (4 * 3600 / LatDArray[scaleNum] - latNum) * LatDArray[scaleNum];
sheetArea.LatMax = sheetArea.LatMin + LatDArray[scaleNum];

sheetArea.LonMax = (lonMillionNum - 30 - 1) * 6 * 3600 + lonNum * LonDArray[scaleNum];
sheetArea.LonMin = sheetArea.LonMax - LonDArray[scaleNum];
return sheetArea;
}

///// <summary>
///// 根据经度获取6度分带
///// </summary>
///// <param name="centerLongitude"></param>
///// <returns>2000国家大地坐标系6度分带带号</returns>
//public static int GetChinaGeodeticCoordinateSystem2000_6DegreesZone(double centerLongitude)
//{
// centerLongitude = centerLongitude / 3600;
// int ZoneNum = Convert.ToInt32(Math.Round((centerLongitude + 3) / 6, 0));
// return ZoneNum;
//}
}
public class SheetArea
{
public double LonMin { get; set; }
public double LatMin { get; set; }
public double LonMax { get; set; }
public double LatMax { get; set; }
public SheetArea() { }
public SheetArea(double lonMin, double latMin, double lonMax, double latMax)
{
LonMin = lonMin;
LatMin = latMin;
LonMax = lonMax;
LatMax = latMax;
}
}

public enum SheetScale : int
{
_1000000 = 0,
_500000 = 1,
_250000 = 2,
//_200000 = 3,
_100000 = 4,
_50000 = 5,
_25000 = 6,
_10000 = 7,
_5000 = 8
}

ArcGIS Pro

ProAppUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class ProAppUtils
{
public static string GetProInstallPath()
{
RegistryKey registryKey = null;
RegistryKey key = null;
try
{
var useRegistryView = Environment.Is64BitOperatingSystem ? RegistryView.Registry64 : RegistryView.Registry32;
registryKey = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, useRegistryView);
key = registryKey.OpenSubKey("SOFTWARE\\ESRI\\ArcGISPro\\Chinese_CN");
if (key == null)
{
Console.WriteLine("未获取到 ArcGIS Pro 安装信息!请检查 ArcGIS Pro 是否正确安装!");
return string.Empty;
}
object proInstallDirObj = key.GetValue("InstallDir");
if (proInstallDirObj == null)
{
Console.WriteLine("未获取到 ArcGIS Pro 安装路径信息!");
return string.Empty;
}
return proInstallDirObj.ToString();
}
catch (Exception ex)
{
Console.WriteLine(ex.GetType().Name + ": " + ex.Message + "\r\n" + ex.StackTrace);
return string.Empty;
}
finally
{
if (registryKey != null)
registryKey.Close();
if (key != null)
key.Close();
}
}
}

ProDialogUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
public class ProDialogUtils
{
public static string OpenFile(string[] FilterItems, string title = "打开文件")
{
OpenItemDialog openItemDialog = new OpenItemDialog()
{
MultiSelect = false,
Title = title,
BrowseFilter= FilterItems.e_ToBrowseProjectFilter()
};
if (!Convert.ToBoolean(openItemDialog.ShowDialog()) || openItemDialog.Items == null || openItemDialog.Items.Count < 1)
return string.Empty;
return openItemDialog.Items[0].Path;
}

public static string[] OpenFiles(string[] FilterItems, string title = "打开文件")
{
OpenItemDialog openItemDialog = new OpenItemDialog()
{
MultiSelect = true,
Title = title,
BrowseFilter = FilterItems.e_ToBrowseProjectFilter()
};
if (!Convert.ToBoolean(openItemDialog.ShowDialog()) || openItemDialog.Items == null || openItemDialog.Items.Count < 1)
return new string[] { };
string[] paths = new string[openItemDialog.Items.Count];
for (int i = 0; i < paths.Length; i++)
paths[i] = openItemDialog.Items[i].Path;
return paths;
}

public static string OpenFolder(string title = "打开文件夹")
{
OpenItemDialog openItemDialog = new OpenItemDialog()
{
MultiSelect = false,
Title = title,
Filter = ItemFilters.Folders
};
if (!Convert.ToBoolean(openItemDialog.ShowDialog()) || openItemDialog.Items == null || openItemDialog.Items.Count < 1)
return string.Empty;
return openItemDialog.Items[0].Path;
}

public static string[] OpenFolders(string title = "打开文件夹")
{
OpenItemDialog openItemDialog = new OpenItemDialog()
{
MultiSelect = true,
Title = title,
Filter = ItemFilters.Folders
};
if (!Convert.ToBoolean(openItemDialog.ShowDialog()) || openItemDialog.Items == null || openItemDialog.Items.Count < 1)
return new string[] { };
string[] paths = new string[openItemDialog.Items.Count];
for (int i = 0; i < paths.Length; i++)
paths[i] = openItemDialog.Items[i].Path;
return paths;
}

public static string SaveFile(string[] FilterItems, string title = "保存")
{
SaveItemDialog saveItemDialog = new SaveItemDialog()
{
Title = title,
BrowseFilter = FilterItems.e_ToBrowseProjectFilter()
};
if (!Convert.ToBoolean(saveItemDialog.ShowDialog()) || saveItemDialog.FilePath == null)
return string.Empty;
return saveItemDialog.FilePath;
}

public static string SaveFolder(string title = "保存")
{
SaveItemDialog saveItemDialog = new SaveItemDialog()
{
Title = title,
Filter = ItemFilters.Folders
};
if (!Convert.ToBoolean(saveItemDialog.ShowDialog()) || saveItemDialog.FilePath == null)
return string.Empty;
return saveItemDialog.FilePath;
}

public static SpatialReference SelectSpatialReference(bool showVerticalCoordinateSystems = false)
{
SpatialReference spatialReference = null;
Wnd_SelectSpatialReference wnd_SelectSpatialReference = new Wnd_SelectSpatialReference(showVerticalCoordinateSystems);
bool? rst = wnd_SelectSpatialReference.ShowDialog();
if (rst != null && (bool)rst)
spatialReference = wnd_SelectSpatialReference.SelectSpatialReference;
return spatialReference;
}
}

ProFeatureClassUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
public class ProFeatureClassUtils
{
/// <summary>
/// 获取要素类可编辑字段,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="sourceFeatureClass">要素类</param>
/// <returns>可编辑字段列表</returns>
public static List<Field> GetEditableFields(FeatureClass sourceFeatureClass)
{
List<Field> editableFields = new List<Field>();
IReadOnlyList<Field> targetFields =
sourceFeatureClass
.GetDefinition()
.GetFields()
.ToList();
foreach (var item in targetFields)
if (item.IsEditable)
editableFields.Add(item);
return editableFields;
}
public static void AddFeature(FeatureClass sourceFeatureClass, FeatureClass targetFeatureClass, IList<long> selectionOID)
{
QueuedTask.Run(async () =>
{
List<Field> editableFields = ProFeatureClassUtils.GetEditableFields(targetFeatureClass);
try
{
await ProFeatureClassUtils.CheckExistFields(sourceFeatureClass, editableFields);
}
catch (GeodatabaseFieldException e)
{
ProMessageUtils.ShowDialog(e.Message);
return;
}
bool addField = await AddField(targetFeatureClass, "originalObjectID", FieldType.Integer);
var queryFilter = new QueryFilter();
using(var featureCursor = sourceFeatureClass.Search(queryFilter))
{
while (featureCursor.MoveNext())
{
var feature = featureCursor.Current as Feature;
long curOID = feature.GetObjectID();
if (!selectionOID.Contains(curOID))
continue;
using (RowBuffer rowBuffer = targetFeatureClass.CreateRowBuffer())
{
Feature newFeature = targetFeatureClass.CreateRow(rowBuffer);
newFeature.SetShape(feature.GetShape());
foreach (var field in newFeature.GetFields())
if (field.IsEditable && field.Name != "originalObjectID")
newFeature[field.Name] = feature[field.Name];
newFeature["originalObjectID"] = curOID;
newFeature.Store();
}
}
}
});
}
public static async Task<bool> AddField(FeatureClass featureClass, string fieldName, FieldType fieldType)
{
return await QueuedTask.Run(() =>
{
FeatureClassDefinition originalFeatureClassDefinition = featureClass.GetDefinition();
FeatureClassDescription originalFeatureClassDescription =
new FeatureClassDescription(originalFeatureClassDefinition);
FieldDescription newFieldDescription =
new FieldDescription(fieldName, fieldType);
List<FieldDescription> modifiedFieldDescriptions =
new List<FieldDescription>(originalFeatureClassDescription.FieldDescriptions)
{
newFieldDescription
};
FeatureClassDescription modifiedFeatureClassDescription =
new FeatureClassDescription(originalFeatureClassDescription.Name,
modifiedFieldDescriptions, originalFeatureClassDescription.ShapeDescription);
Geodatabase geodatabase = featureClass.GetDatastore() as Geodatabase;
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
schemaBuilder.Modify(modifiedFeatureClassDescription);
bool modifyStatus = schemaBuilder.Build();
if (!modifyStatus)
{
string msg = "";
IReadOnlyList<string> errors = schemaBuilder.ErrorMessages;
foreach (var item in errors)
msg += item.ToString() + "\r\n";
LogUtils.AppLog(msg);
return false;
}
return true;
});
}
public static async Task CheckExistFields(FeatureClass targetFeatureClass, IEnumerable<Field> fields)
{
await QueuedTask.Run(() =>
{
IReadOnlyList<Field> targetFields = targetFeatureClass.GetDefinition().GetFields();
foreach (Field field in fields)
{
bool fieldExist = false;
foreach (Field targetField in targetFields)
{
if (field.Name.Equals(targetField.Name, StringComparison.OrdinalIgnoreCase) &&
field.FieldType == targetField.FieldType)
{
fieldExist = true;
break;
}
}
if (!fieldExist)
throw new GeodatabaseFieldException(
$"未找到字段:{{Name: {field.Name}, FieldType: {field.FieldType}}}");
}
});
}
public static void AddFeature(FeatureClass sourceFeatureClass, FeatureClass targetFeatureClass)
{
var ps = new ProgressorSource("添加要素...");
QueuedTask.Run(async () =>
{
List<Field> editableFields = ProFeatureClassUtils.GetEditableFields(targetFeatureClass);
try
{
await ProFeatureClassUtils.CheckExistFields(sourceFeatureClass, editableFields);
}
catch (GeodatabaseFieldException e)
{
ProMessageUtils.ShowDialog(e.Message);
return;
}
using (RowCursor featureCursor = sourceFeatureClass.Search())
{
while (featureCursor.MoveNext())
{
Feature feature = featureCursor.Current as Feature;
long curOID = feature.GetObjectID();
using (RowBuffer rowBuffer = targetFeatureClass.CreateRowBuffer())
{
Feature newFeature = targetFeatureClass.CreateRow(rowBuffer);
newFeature.SetShape(feature.GetShape());
foreach (var field in newFeature.GetFields())
if (field.IsEditable)
newFeature[field.Name] = feature[field.Name];
newFeature.Store();
}
}
}
}, ps.Progressor);
}
/// <summary>
/// 更新/插入要素,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="sourceFeatureClass">源要素类</param>
/// <param name="targetFeatureClass">目标要素类</param>
/// <param name="keyFields">主键字段</param>
/// <param name="ps">进度器</param>
/// <returns>结果</returns>
public static bool UpdateOrInsert(FeatureClass sourceFeatureClass, FeatureClass targetFeatureClass, string[] keyFields, ProgressorSource ps = null)
{
if (keyFields != null)
{
foreach (string keyField in keyFields)
{
int targetKeyFieldIdx = targetFeatureClass.GetDefinition().FindField(keyField);
if (targetKeyFieldIdx < 0)
{
ProMessageUtils.ShowDialog(
$"目标要素类不包含主键字段:{keyField}!",
"错误", System.Windows.MessageBoxButton.OK,
System.Windows.MessageBoxImage.Error);
return false;
}
int sourceKeyFieldIdx = sourceFeatureClass.GetDefinition().FindField(keyField);
if (sourceKeyFieldIdx < 0)
{
ProMessageUtils.ShowDialog(
$"源要素类不包含主键字段:{keyField}!",
"错误", System.Windows.MessageBoxButton.OK,
System.Windows.MessageBoxImage.Error);
return false;
}
}
}
long num = 0;
long count = sourceFeatureClass.GetCount();
using (RowCursor sourceFeatureCursor = sourceFeatureClass.Search())
{
while (sourceFeatureCursor.MoveNext())
{
if (ps != null)
ps.Progressor.Message = $"更新数据...({++num}/{count})";
Feature sourceFeature = sourceFeatureCursor.Current as Feature;
if (sourceFeature == null)
continue;
bool isExistsFeature = false;
if (keyFields != null)
{
QueryFilter filter = new QueryFilter();
for (int i = 0; i < keyFields.Length; i++)
{
object keyFieldValue = sourceFeature[keyFields[i]];
filter.WhereClause += (i == 0 ? "" : " AND ") + $"{keyFields[i]}='{keyFieldValue}'";
}
using (RowCursor targetFeatureCursor = targetFeatureClass.Search(filter))
{
while (targetFeatureCursor.MoveNext())
{
Feature targetFeature = targetFeatureCursor.Current as Feature;
if (targetFeature == null)
continue;
targetFeature.SetShape(sourceFeature.GetShape());
foreach (var field in targetFeature.GetFields())
{
if (field.IsEditable)
{
try
{
targetFeature[field.Name] = sourceFeature[field.Name];
}
catch (Exception ex)
{
LogUtils.AppLog("要素更新异常!", Enum.LogLevel.Warning, ex);
}
}
}
targetFeature.Store();
isExistsFeature = true;
}
}
}
if (isExistsFeature)
continue;
using (RowBuffer rowBuffer = targetFeatureClass.CreateRowBuffer())
{
Feature newFeature = targetFeatureClass.CreateRow(rowBuffer);
newFeature.SetShape(sourceFeature.GetShape());
foreach (var field in newFeature.GetFields())
{
if (field.IsEditable)
{
try
{
newFeature[field.Name] = sourceFeature[field.Name];
}
catch (Exception ex)
{
LogUtils.AppLog("要素更新异常!", Enum.LogLevel.Warning, ex);
}
}
}
newFeature.Store();
}
}
}
return true;
}
}

ProFeatureLayerUtils

1
2
3
4
5
6
7
8
9
10
public class ProFeatureLayerUtils
{
public static async Task<FeatureClass> GetFeatureClass(FeatureLayer featureLayer)
{
return await QueuedTask.Run(() =>
{
return featureLayer.GetFeatureClass();
});
}
}

ProGdbUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
public class ProGdbUtils
{
public static async Task<Geodatabase> CreateGDBMCT(string gdbPath)
{
var ps = new ProgressorSource("正在创建文件地理数据库...");
return await QueuedTask.Run(() =>
{
string folderPath = System.IO.Path.GetDirectoryName(gdbPath);
if (!Directory.Exists(folderPath))
Directory.CreateDirectory(folderPath);
FileGeodatabaseConnectionPath fileGeodatabaseConnectionPath = new FileGeodatabaseConnectionPath(new Uri(gdbPath));
Geodatabase geodatabase = SchemaBuilder.CreateGeodatabase(fileGeodatabaseConnectionPath);
return geodatabase;
}, ps.Progressor);
}

public static async Task<Geodatabase> OpenOrCreateGDBMCT(string gdbPath)
{
var ps = new ProgressorSource("正在创建文件地理数据库...");
return await QueuedTask.Run(() =>
{
Geodatabase geodatabase = null;
try
{
geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(gdbPath)));
}
catch
{
string folderPath = System.IO.Path.GetDirectoryName(gdbPath);
if (!Directory.Exists(folderPath))
Directory.CreateDirectory(folderPath);
FileGeodatabaseConnectionPath fileGeodatabaseConnectionPath = new FileGeodatabaseConnectionPath(new Uri(gdbPath));
geodatabase = SchemaBuilder.CreateGeodatabase(fileGeodatabaseConnectionPath);
}
return geodatabase;
}, ps.Progressor);
}

/// <summary>
/// 创建文件地理数据库,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="gdbPath">gdb路径</param>
/// <param name="ps">进度器</param>
/// <returns>新GDB</returns>
public static Geodatabase CreateGDB(string gdbPath, ProgressorSource ps = null)
{
if (ps != null)
ps.Progressor.Message = "正在创建文件地理数据库...";
string folderPath = System.IO.Path.GetDirectoryName(gdbPath);
if (!Directory.Exists(folderPath))
Directory.CreateDirectory(folderPath);
FileGeodatabaseConnectionPath fileGeodatabaseConnectionPath = new FileGeodatabaseConnectionPath(new Uri(gdbPath));
Geodatabase geodatabase = SchemaBuilder.CreateGeodatabase(fileGeodatabaseConnectionPath);
return geodatabase;
}

public static async Task<Geodatabase> GetTempGDB()
{
try
{
var ps = new ProgressorSource("正在获取缓存文件地理数据库...");
return await QueuedTask.Run(() =>
{
Geodatabase geodatabase = null;
geodatabase =
new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(AppConfig.Path_File_Temp_GDB)));
return geodatabase;
}, ps.Progressor);
}
catch (GeodatabaseNotFoundOrOpenedException exception)
{
if (Directory.Exists(AppConfig.Path_File_Temp_GDB))
Directory.Delete(AppConfig.Path_File_Temp_GDB, true);
return await CreateGDBMCT(AppConfig.Path_File_Temp_GDB);
}
}

public static FeatureClass CreateFeatureClass(
Geodatabase geodatabase, FeatureClass featureClass, string featureClassName = null)
{
FeatureClass newFeatureClass = null;
var ps = new ProgressorSource("正在创建要素类...");
FeatureClassDescription featureClassDescription = null;
if (featureClassName != null)
{
FeatureClassDefinition _featureClassDefinition_ = featureClass.GetDefinition();
FeatureClassDescription _featureClassDescription_ = new FeatureClassDescription(_featureClassDefinition_);
featureClassDescription = new FeatureClassDescription(featureClassName, _featureClassDescription_.FieldDescriptions, _featureClassDescription_.ShapeDescription);
}
else
{
FeatureClassDefinition featureClassDefinition = featureClass.GetDefinition();
featureClassDescription = new FeatureClassDescription(featureClassDefinition);
}
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
schemaBuilder.Create(featureClassDescription);
bool createClass = schemaBuilder.Build();
if (!createClass)
{
LogUtils.AppLog(schemaBuilder.ErrorMessages.ToArray().e_Connect("\r\n"));
return null;
}
if (featureClassName == null)
newFeatureClass = geodatabase.OpenDataset<FeatureClass>(featureClass.GetName());
else
newFeatureClass = geodatabase.OpenDataset<FeatureClass>(featureClassName);
return newFeatureClass;
}

public static async Task<FeatureClass> CreateFeatureClass(
Geodatabase geodatabase,
string featureClassName,
ShapeDescription shapeDescription,
IList<FieldDescription> fieldDescriptions)
{
FeatureClass newFeatureClass = null;
var ps = new ProgressorSource("正在创建要素类...");
await QueuedTask.Run(() =>
{
FeatureClassDescription featureClassDescription =
new FeatureClassDescription(
featureClassName,
fieldDescriptions,
shapeDescription);
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
schemaBuilder.Create(featureClassDescription);
bool success = schemaBuilder.Build();
if (success)
{
newFeatureClass = geodatabase.OpenDataset<FeatureClass>(featureClassName);
}
else
{
string error = schemaBuilder.ErrorMessages.ToArray().e_Connect("\r\n");
LogUtils.AppLog("创建要素类失败!\r\n" + error, Enum.LogLevel.Error);
}
},ps.Progressor);
return newFeatureClass;
}

public static async Task RunInSourceSDE(Func<Geodatabase, Task> action)
{
Geodatabase geodatabase = null;
try
{
geodatabase = await OpenEnterpriseGeodatabase(
AppConfig.Static.Source_SDE_Inst,
AppConfig.Static.Source_SDE_Db,
AppConfig.Static.Source_SDE_Usr,
AppConfig.Static.Source_SDE_Pwd);
if (geodatabase == null)
ProMessageUtils.ShowDialog("SDE库连接失败!", "错误",
System.Windows.MessageBoxButton.OK,
System.Windows.MessageBoxImage.Warning);
await action(geodatabase);
}
catch(Exception ex)
{
LogUtils.AppLog(ex.Message, Enum.LogLevel.Error, ex);
}
}

public static async Task RunInGeoEntitySDE(Func<Geodatabase, Task> action)
{
Geodatabase geodatabase = null;
try
{
geodatabase = await OpenEnterpriseGeodatabase(
AppConfig.Static.GeoEntity_SDE_Inst,
AppConfig.Static.GeoEntity_SDE_Db,
AppConfig.Static.GeoEntity_SDE_Usr,
AppConfig.Static.GeoEntity_SDE_Pwd);
if (geodatabase == null)
ProMessageUtils.ShowDialog("SDE库连接失败!", "错误",
System.Windows.MessageBoxButton.OK,
System.Windows.MessageBoxImage.Warning);
await action(geodatabase);
}
catch (Exception ex)
{
LogUtils.AppLog(ex.Message, Enum.LogLevel.Error, ex);
}
}

/// <summary>
/// 检查要素类是否已创建,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="geodatabase">地理数据库</param>
/// <param name="featureClassName">要素类名</param>
/// <returns>结果</returns>
public static bool FeatureClassExists(Geodatabase geodatabase, string featureClassName, ProgressorSource ps = null)
{
bool featureClassExists = false;
if (ps != null)
ps.Progressor.Message = "检查表是否已创建...";
try
{
IReadOnlyList<FeatureClassDefinition> featureClassDefinitions = geodatabase.GetDefinitions<FeatureClassDefinition>();
FeatureClassDefinition featureClassDefinition = geodatabase.GetDefinition<FeatureClassDefinition>(featureClassName);
featureClassDefinition.Dispose();
featureClassExists = true;
}
catch
{
// GetDefinition throws an exception if the definition doesn't exist
}
return featureClassExists;
}

/// <summary>
/// 检查表是否已创建,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="geodatabase">地理数据库</param>
/// <param name="tableName">表名</param>
/// <param name="ps">进度器</param>
/// <returns>表是否已创建</returns>
public static bool TableExists(Geodatabase geodatabase, string tableName, ProgressorSource ps = null)
{
bool tableExists = false;
if (ps != null)
ps.Progressor.Message = "检查表是否已创建...";
try
{
IReadOnlyList<TableDefinition> tableDefinitions = geodatabase.GetDefinitions<TableDefinition>();
TableDefinition tableDefinition = geodatabase.GetDefinition<TableDefinition>(tableName);
tableDefinition.Dispose();
tableExists = true;
}
catch
{
// GetDefinition throws an exception if the definition doesn't exist
}
return tableExists;
}

/// <summary>
/// 创建表,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="geodatabase">地理数据库</param>
/// <param name="tableName">表名</param>
/// <param name="dataTable">数据表结构</param>
/// <param name="ps">进度器</param>
/// <returns>新表</returns>
public static Table CreateTable(Geodatabase geodatabase, string tableName, DataTable dataTable, ProgressorSource ps = null)
{
Table table = null;
try
{
if (ps != null)
ps.Progressor.Message = "创建表...";
FieldDescription globalIDFieldDescription = FieldDescription.CreateGlobalIDField();
FieldDescription objectIDFieldDescription = FieldDescription.CreateObjectIDField();
List<FieldDescription> fieldDescriptions = new List<FieldDescription>()
{
globalIDFieldDescription, objectIDFieldDescription
};
for (int i = 0; i < dataTable.Columns.Count; i++)
{
FieldDescription? fieldDescription1 = fieldDescriptions.Find(f => f.Name.ToLower() == dataTable.Columns[i].ColumnName.ToLower());
if (fieldDescription1 != null) continue;
FieldDescription fieldDescription = FieldDescription.CreateStringField(dataTable.Columns[i].ColumnName, 512);
fieldDescriptions.Add(fieldDescription);
}
TableDescription tableDescription = new TableDescription(tableName, fieldDescriptions);
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
schemaBuilder.Create(tableDescription);
bool success = schemaBuilder.Build();
if (!success)
{
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;
foreach (var item in errorMessages)
LogUtils.AppLog("表创建失败!\r\n" + item, Enum.LogLevel.Error);
}
table = geodatabase.OpenDataset<Table>(tableName);
}
catch (Exception ex)
{
ProMessageUtils.ShowDialog(ex.Message);
}
return table;
}

/// <summary>
/// 创建表,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="geodatabase">地理数据库</param>
/// <param name="tableName">表名</param>
/// <param name="dataTable">数据表结构</param>
/// <param name="ps">进度器</param>
/// <returns>新表</returns>
public static Table CreateTable(Geodatabase geodatabase, string tableName, Table table, ProgressorSource ps = null)
{
Table newTable = null;
try
{
if (ps != null)
ps.Progressor.Message = "创建表...";
FieldDescription globalIDFieldDescription = FieldDescription.CreateGlobalIDField();
FieldDescription objectIDFieldDescription = FieldDescription.CreateObjectIDField();
List<FieldDescription> fieldDescriptions = new List<FieldDescription>()
{
globalIDFieldDescription, objectIDFieldDescription
};
foreach (var field in table.GetDefinition().GetFields())
{
FieldDescription? fieldDescription1 = fieldDescriptions.Find(f => f.Name.ToLower() == field.Name.ToLower());
if (fieldDescription1 != null) continue;
FieldDescription fieldDescription = new FieldDescription(field);
fieldDescriptions.Add(fieldDescription);
}
TableDescription tableDescription = new TableDescription(tableName, fieldDescriptions);
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);
schemaBuilder.Create(tableDescription);
bool success = schemaBuilder.Build();
if (!success)
{
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;
foreach (var item in errorMessages)
LogUtils.AppLog("表创建失败!\r\n" + item, Enum.LogLevel.Error);
}
newTable = geodatabase.OpenDataset<Table>(tableName);
}
catch (Exception ex)
{
ProMessageUtils.ShowDialog(ex.Message);
}
return newTable;
}

public static async Task<Geodatabase> OpenEnterpriseGeodatabase(
string instance,
string database,
string user,
string password,
EnterpriseDatabaseType enterpriseDatabaseType = EnterpriseDatabaseType.PostgreSQL)
{
Geodatabase geodatabase = null;
var ps = new ProgressorSource("连接企业级SDE数据库...");
await QueuedTask.Run(() =>
{
try
{
DatabaseConnectionProperties connectionProperties =
new DatabaseConnectionProperties(enterpriseDatabaseType)
{
AuthenticationMode = AuthenticationMode.DBMS,
Instance = instance,
Database = database,
User = user,
Password = password
};
geodatabase = new Geodatabase(connectionProperties);
}
catch (Exception ex)
{
LogUtils.AppLog("连接SDE数据库失败!", Enum.LogLevel.Warning, ex);
}
}, ps.Progressor);
return geodatabase;
}
}

ProShpUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class ProShpUtils
{
public static async Task<FeatureClass> OpenShapefileFeatureClass(string shapefilePath)
{
string folderPath = System.IO.Path.GetDirectoryName(shapefilePath);
string shapeFileName = System.IO.Path.GetFileName(shapefilePath);
FeatureClass featureClass = null;
await ArcGIS.Desktop.Framework.Threading.Tasks.QueuedTask.Run(() =>
{
FileSystemDatastore fileSystemDatastore = null;
try
{
var fileConnection = new FileSystemConnectionPath(
new Uri(folderPath), FileSystemDatastoreType.Shapefile);
fileSystemDatastore = new FileSystemDatastore(fileConnection);
featureClass = fileSystemDatastore.OpenDataset<FeatureClass>(shapeFileName);
//FeatureClass taxLotsFeatureClass = shapefile.OpenDataset<FeatureClass>("TaxLots");
//FeatureClass manHolesFeatureClass = shapefile.OpenDataset<FeatureClass>("ManHoles.shp"); // Can use the .shp extension, but its not needed.
//Table taxDetailsTableWithoutExtension = shapefile.OpenDataset<Table>("TaxDetails");
//Table taxDetailsTable = shapefile.OpenDataset<Table>("TaxDetails.dbf");
}
catch(Exception ex)
{
LogUtils.AppLog("获取ShapeFile文件FeatureClass失败!", Enum.LogLevel.Warning, ex);
}
finally { if (fileSystemDatastore != null) { fileSystemDatastore.Dispose(); } }
});
return featureClass;
}

public static void Create()
{
string folderPath = "E:\\files\\work\\arcgis files\\pro\\MyProject\\data\\ShapeFile";
FileSystemDatastore fileSystemDatastore = null;
try
{
var fileConnection = new FileSystemConnectionPath(
new Uri(folderPath), FileSystemDatastoreType.Shapefile);
fileSystemDatastore = new FileSystemDatastore(fileConnection);
}
catch(Exception ex)
{

}
finally { if (fileSystemDatastore != null) { fileSystemDatastore.Dispose(); } }
}
}

ProStyleUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class ProStyleUtils
{
public static async Task<StyleProjectItem >GetAppStyleProjectItem()
{
string name = Path.GetFileNameWithoutExtension(AppConfig.Path_File_AppStyle_Symbol);
IEnumerable<StyleProjectItem> enumerable = Project.Current.GetItems<StyleProjectItem>();
StyleProjectItem? styleProjectItem = enumerable.FirstOrDefault(s => s.Name == name);
if(styleProjectItem == null)
{
if (!File.Exists(AppConfig.Path_File_AppStyle_Symbol))
{
ProMessageUtils.ShowDialog("未找到系统样式文件:\r\n" + AppConfig.Path_File_AppStyle_Symbol, "提示", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Warning);
return null;
}
await QueuedTask.Run(() =>
{
Project.Current.AddStyle(AppConfig.Path_File_AppStyle_Symbol);
});
enumerable = Project.Current.GetItems<StyleProjectItem>();
styleProjectItem = enumerable.FirstOrDefault(s => s.Name == name);
}
return styleProjectItem;
}
}

ProTableUtils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
public class ProTableUtils
{
/// <summary>
/// 更新/插入表记录,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="table">目标数据表</param>
/// <param name="dataTable">源数据表</param>
/// <param name="PrimKey">主键字段</param>
/// <param name="ps">进度器</param>
/// <returns>结果</returns>
public static bool UpdateOrInsert(Table table, DataTable dataTable, string PrimKey, ProgressorSource ps = null)
{
bool containsPriKeyCol = dataTable.Columns.Contains(PrimKey);
if (!containsPriKeyCol)
{
ProMessageUtils.ShowDialog($"数据表中缺失主键字段:[{PrimKey}]!", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
return false;
}
for (int i = 0; i < dataTable.Rows.Count; i++)
{
if (ps != null)
ps.Message = $"更新数据...({i + 1}/{dataTable.Rows.Count})";
DataRow row = dataTable.Rows[i];
bool recordIsExists = false;
if (!string.IsNullOrEmpty(PrimKey))
{
object val = row[PrimKey];
QueryFilter queryFilter = new QueryFilter();
queryFilter.WhereClause = $"{PrimKey}='{val}'";
using (RowCursor rowCursor = table.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
recordIsExists = true;
foreach (DataColumn col in dataTable.Columns)
{
try
{
rowCursor.Current[col.ColumnName] = row[col];
}
catch (Exception ex)
{
LogUtils.AppLog("更新实体数据异常!", Enum.LogLevel.Error, ex);
}
}
rowCursor.Current.Store();
}
}
}
if (!recordIsExists)
{
using (RowBuffer rowBuffer = table.CreateRowBuffer())
using (Row tableRow = table.CreateRow(rowBuffer))
{
foreach (DataColumn col in dataTable.Columns)
{
try
{
Field field = tableRow.GetFields().FirstOrDefault(f => f.Name.ToLower() == col.ColumnName.ToLower());
if (field != null && field.IsEditable)
tableRow[col.ColumnName] = row[col];
}
catch (Exception ex)
{
LogUtils.AppLog("插入实体数据异常!", Enum.LogLevel.Error, ex);
}
}
tableRow.Store();
}
}
}
return true;
}

/// <summary>
/// 更新/插入表记录,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="table">目标数据表</param>
/// <param name="dataTable">源数据表</param>
/// <param name="PrimKey">主键字段</param>
/// <param name="ps">进度器</param>
/// <returns>结果</returns>
public static bool UpdateOrInsert(Table table, DataTable dataTable, string[] PrimKey, ProgressorSource ps = null)
{
foreach (string key in PrimKey)
{
bool containsPriKeyCol = dataTable.Columns.Contains(key);
if (!containsPriKeyCol)
{
ProMessageUtils.ShowDialog($"数据表中缺失主键字段:[{key}]!", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
return false;
}
}
for (int i = 0; i < dataTable.Rows.Count; i++)
{
if (ps != null)
ps.Message = $"更新数据...({i + 1}/{dataTable.Rows.Count})";
DataRow row = dataTable.Rows[i];
QueryFilter queryFilter = new QueryFilter();
for (int k = 0; k < PrimKey.Length; k++)
{
object val = row[PrimKey[k]];
queryFilter.WhereClause += (k == 0 ? "" : " AND ") + $"{PrimKey[k]}='{val}'";
}
bool recordIsExists = false;
using (RowCursor rowCursor = table.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
recordIsExists = true;
foreach (DataColumn col in dataTable.Columns)
{
try
{
rowCursor.Current[col.ColumnName] = row[col];
}
catch (Exception ex)
{
LogUtils.AppLog("更新实体数据异常!", Enum.LogLevel.Error, ex);
}
}
rowCursor.Current.Store();
}
}
if (!recordIsExists)
{
using (RowBuffer rowBuffer = table.CreateRowBuffer())
using (Row tableRow = table.CreateRow(rowBuffer))
{
foreach (DataColumn col in dataTable.Columns)
{
try
{
object v = row[col];
tableRow[col.ColumnName] = v;
}
catch (Exception ex)
{
LogUtils.AppLog("插入实体数据异常!", Enum.LogLevel.Error, ex);
}
}
tableRow.Store();
}
}
}
return true;
}

/// <summary>
/// 更新/插入表记录,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="table">目标数据表</param>
/// <param name="tableSource">源数据表</param>
/// <param name="PrimKey">主键字段</param>
/// <param name="ps">进度器</param>
/// <returns>结果</returns>
public static bool UpdateOrInsert(Table table, Table tableSource, string PrimKey, ProgressorSource ps = null)
{
IReadOnlyList<Field> fieldsSource = tableSource.GetDefinition().GetFields();
if (!string.IsNullOrEmpty(PrimKey))
{
Field field = fieldsSource.FirstOrDefault(f => f.Name.ToLower() == PrimKey.ToLower());
if (field == null)
{
ProMessageUtils.ShowDialog($"数据表中缺失主键字段:[{PrimKey}]!", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
return false;
}
}
using (RowCursor rowCursorSource = tableSource.Search())
{
long count = tableSource.GetCount();
long i = 0;
while (rowCursorSource.MoveNext())
{
if (ps != null)
ps.Progressor.Message = $"更新数据...({++i}/{count})";
bool recordIsExists = false;
if (!string.IsNullOrEmpty(PrimKey))
{
object valPrim = rowCursorSource.Current[PrimKey];
QueryFilter queryFilter = new QueryFilter();
queryFilter.WhereClause = $"{PrimKey}='{valPrim}'";
using (RowCursor rowCursor = table.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
recordIsExists = true;
foreach (Field fld in fieldsSource)
{
try
{
rowCursor.Current[fld.Name] = rowCursorSource.Current[fld.Name];
}
catch (Exception ex)
{
LogUtils.AppLog("更新实体数据异常!", Enum.LogLevel.Error, ex);
}
}
rowCursor.Current.Store();
}
}
}
if (!recordIsExists)
{
using (RowBuffer rowBuffer = table.CreateRowBuffer())
using (Row tableRow = table.CreateRow(rowBuffer))
{
foreach (Field fld in fieldsSource)
{
try
{
Field? field = tableRow.GetFields().FirstOrDefault(f => f.Name == fld.Name);
if (field == null || !field.IsEditable)
continue;
tableRow[fld.Name] = rowCursorSource.Current[fld.Name];
}
catch (Exception ex)
{
LogUtils.AppLog("插入实体数据异常!", Utils.Enum.LogLevel.Error, ex);
}
}
tableRow.Store();
}
}
}
}
return true;
}

/// <summary>
/// 更新/插入表记录,必须在QueueTask.Run中执行!
/// </summary>
/// <param name="table">目标数据表</param>
/// <param name="tableSource">源数据表</param>
/// <param name="PrimKey">主键字段</param>
/// <param name="ps">进度器</param>
/// <returns>结果</returns>
public static bool UpdateOrInsert(Table table, Table tableSource, string[] PrimKey, ProgressorSource ps = null)
{
IReadOnlyList<Field> fieldsSource = tableSource.GetDefinition().GetFields();
foreach (string key in PrimKey)
{
Field field = fieldsSource.FirstOrDefault(f => f.Name.ToLower() == key.ToLower());
if (field == null)
{
ProMessageUtils.ShowDialog($"数据表中缺失主键字段:[{key}]!", "错误", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error);
return false;
}
}
using (RowCursor rowCursorSource = tableSource.Search())
{
long count = tableSource.GetCount();
long i = 0;
while (rowCursorSource.MoveNext())
{
if (ps != null)
ps.Message = $"更新数据...({++i}/{count})";
QueryFilter queryFilter = new QueryFilter();
for (int k = 0; k < PrimKey.Length; k++)
{
object valPrim = rowCursorSource.Current[PrimKey[k]];
queryFilter.WhereClause += (k == 0 ? "" : " AND ") + $"{PrimKey[k]}='{valPrim}'";
}
bool recordIsExists = false;
using (RowCursor rowCursor = table.Search(queryFilter))
{
while (rowCursor.MoveNext())
{
recordIsExists = true;
foreach (Field fld in fieldsSource)
{
try
{
rowCursor.Current[fld.Name] = rowCursorSource.Current[fld.Name];
}
catch (Exception ex)
{
LogUtils.AppLog("更新实体数据异常!", Enum.LogLevel.Error, ex);
}
}
rowCursor.Current.Store();
}
}
if (!recordIsExists)
{
using (RowBuffer rowBuffer = table.CreateRowBuffer())
using (Row tableRow = table.CreateRow(rowBuffer))
{
foreach (Field fld in fieldsSource)
{
try
{
tableRow[fld.Name] = rowCursorSource.Current[fld.Name];
}
catch (Exception ex)
{
LogUtils.AppLog("插入实体数据异常!", Utils.Enum.LogLevel.Error, ex);
}
}
tableRow.Store();
}
}
}
}
return true;
}
}