arcgis开发常用源码
arcgis開發常用源碼
1.點上生成面的代碼
if (m_pFeatureLayer.FeatureClass.ShapeType == esriGeometryType.esriGeometryPolygon) { IPointCollection m_pPointCollection = new PolygonClass(); object missing = Type.Missing; int icount = newFeature.XLIST.Count; if (icount < 3) return; for (int i = 0; i < icount; i++) { IPoint point = new PointClass(); point.PutCoords(newFeature.XLIST, newFeature.YLIST); m_pPointCollection.AddPoint(point, ref missing, ref missing); } IPolygon m_pPolygon = m_pPointCollection as IPolygon; if (m_pPolygon == null) { System.Windows.Forms.MessageBox.Show("null"); return; } else { ITopologicalOperator pTopo = m_pPolygon as ITopologicalOperator; if (pTopo != null) { pTopo.Simplify(); } } IWorkspaceEdit m_pWorkspaceEdit = m_EngineEditor.EditWorkspace as IWorkspaceEdit; m_pWorkspaceEdit.StartEditOperation(); IFeature m_pFeature = m_pFeatureLayer.FeatureClass.CreateFeature(); m_pFeature.Shape = m_pPolygon as IGeometry; m_pFeature.Store(); m_pWorkspaceEdit.StopEditOperation(); }
2.文件的打開 保存 另存的代碼
using System;
using System.Windows.Forms;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Carto;
namespace SaveMapDocument
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class SaveMapDocument : System.Windows.Forms.Form
{
public System.Windows.Forms.TextBox txtMapDocument;
public System.Windows.Forms.Button cmdOpen;
public System.Windows.Forms.Button cmdSave;
public System.Windows.Forms.Button cmdSaveAs;
private System.Windows.Forms.OpenFileDialog openFileDialog1;
private System.Windows.Forms.SaveFileDialog saveFileDialog1;
private IMapDocument m_MapDocument;
private ESRI.ArcGIS.Controls.AxToolbarControl axToolbarControl1;
private ESRI.ArcGIS.Controls.AxPageLayoutControl axPageLayoutControl1;
private ESRI.ArcGIS.Controls.AxLicenseControl axLicenseControl1;
private ESRI.ArcGIS.Controls.AxTOCControl axTOCControl1;
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.Container components = null;
public SaveMapDocument()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
//Release COM objects
ESRI.ArcGIS.ADF.COMSupport.AOUninitialize.Shutdown();
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.Run(new SaveMapDocument());
}
private void Form1_Load(object sender, System.EventArgs e)
{
//Add toolbar definitions to the ToolbarControl
axToolbarControl1.AddToolbarDef("esriControls.ControlsPageLayoutToolbar", -1, false, 0, esriCommandStyles.esriCommandStyleIconOnly);
axToolbarControl1.AddToolbarDef("esriControls.ControlsGraphicElementToolbar", -1, true, 0, esriCommandStyles.esriCommandStyleIconOnly);
//Set buddy control
axToolbarControl1.SetBuddyControl(axPageLayoutControl1);
axTOCControl1.SetBuddyControl(axPageLayoutControl1);
cmdSave.Enabled = false;
cmdSaveAs.Enabled = false;
}
private void cmdOpen_Click(object sender, System.EventArgs e)
{
//Open a file dialog for opening map documents
openFileDialog1.Title = "Open Map Document";
openFileDialog1.Filter = "Map Documents (*.mxd)|*.mxd";
openFileDialog1.ShowDialog();
// Exit if no map document is selected
string sFilePath = openFileDialog1.FileName;
if (sFilePath == "")
{
return;
}
//Open document
OpenDocument((sFilePath));
if (cmdSave.Enabled == false)
{
cmdSave.Enabled = true;
}
if (cmdSaveAs.Enabled == false)
{
cmdSaveAs.Enabled = true;
}
}
private void cmdSave_Click(object sender, System.EventArgs e)
{
//Save changes to the current document
SaveDocument();
}
private void cmdSaveAs_Click(object sender, System.EventArgs e) 另存為
{
//Open a file dialog for saving map documents
saveFileDialog1.Title = "Save Map Document As";
saveFileDialog1.Filter = "Map Documents (*.mxd)|*.mxd";
saveFileDialog1.ShowDialog();
//Exit if no map document is selected
string sFilePath = saveFileDialog1.FileName;
if (sFilePath == "")
{
return;
}
if (sFilePath == m_MapDocument.DocumentFilename)
{
//Save changes to the current document
SaveDocument();
}
else
{
//SaveAs a new document with relative paths
m_MapDocument.SaveAs(sFilePath, true, true);
//Open document
OpenDocument((sFilePath));
MessageBox.Show("Document saved successfully!");
}
}
private void OpenDocument(string sFilePath)
{
if (m_MapDocument != null) m_MapDocument.Close();
//Create a new map document
m_MapDocument = new MapDocumentClass();
//Open the map document selected
m_MapDocument.Open(sFilePath,"");
//Set the PageLayoutControl page layout to the map document page layout
axPageLayoutControl1.PageLayout = m_MapDocument.PageLayout;
txtMapDocument.Text = m_MapDocument.DocumentFilename;
}
private void SaveDocument()
{
//Check that the document is not read only
if (m_MapDocument.get_IsReadOnly(m_MapDocument.DocumentFilename) == true)
{
MessageBox.Show("This map document is read only!");
return;
}
//Save with the current relative path setting
m_MapDocument.Save(m_MapDocument.UsesRelativePaths,true);
MessageBox.Show("Changes saved successfully!");
}
}
}
3.訪問一個地圖
static void OpenMXDViaMapDocument(string path)
{
IMapDocument pMapDocument = new MapDocumentClass();
if (pMapDocument.get_IsMapDocument(path))
{
pMapDocument.Open(path,null);
IMap pMap;
for (int i = 0; i <= pMapDocument.MapCount - 1; i++)
{
pMap = pMapDocument.get_Map(i);
Console.WriteLine(pMap.Name);
IEnumLayer pEnumLayer = pMap.get_Layers(null,true);
pEnumLayer.Reset();
ILayer pLayer = pEnumLayer.Next();
while (pLayer != null)
{
Console.WriteLine(pLayer.Name);
pLayer = pEnumLayer.Next();
}
}
}
}
4、地圖坐標
private void axMapControl1_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
{
string outx = null;
string outy = null;
IActiveView pActiveView = axMapControl1.ActiveView;
BJAEINFunction.bj54tojingweiduAo(pActiveView, e.mapX, e.mapY, ref outx, ref outy);
labelItem1.Text = "地理坐標: 經度:" + outx + " 緯度:" + outy;
//IFeatureLayer pFeatLyr;
//pFeatLyr = axMapControl1.Map.get_Layer(2) as IFeatureLayer;
//pFeatLyr.DisplayField = "面積";
//pFeatLyr.ShowTips = true;
//string pTips;
//pTips = pFeatLyr.get_TipText(e.mapX, e.mapY, pActiveView.FullExtent.Width / 100);
//toolTip1.SetToolTip(axMapControl1, pTips);
}
5、大地轉北京54
public static void bj54tojingweiduAo(IActiveView pActiveView, double inx, double iny, ref string outx, ref string outy)
{
try
{
IMap pMap = pActiveView.FocusMap;
SpatialReferenceEnvironment pSpRE = new SpatialReferenceEnvironment();
IGeographicCoordinateSystem pGeoCS = pSpRE.CreateGeographicCoordinateSystem((int)esriSRGeoCSType.esriSRGeoCS_Beijing1954);
ISpatialReference pSpr = pGeoCS;
IPoint pPoint = new ESRI.ArcGIS.Geometry.Point();
pPoint.X = inx;
pPoint.Y = iny;
IGeometry pGeo = pPoint;
pGeo.SpatialReference = pMap.SpatialReference;
pGeo.Project(pSpr);//坐標轉換,由當前地圖坐標轉為北京54經緯度坐標
double jwd_jd = pPoint.X;
double jwd_wd = pPoint.Y;
//轉化成度、分、秒
//經度
int Jd, Wd, Jf, Wf;
double temp;
Single Jm, Wm;
Jd = (int)jwd_jd; //度
temp = (jwd_jd - Jd) * 60;
Jf = (int)temp; //分
temp = (temp - Jf) * 60;
Jm = Convert.ToInt32(temp); //秒
//緯度
Wd = (int)jwd_wd; //度
temp = (jwd_wd - Wd) * 60;
Wf = (int)temp; //分
temp = (temp - Wf) * 60;
Wm = Convert.ToInt32(temp); //秒
outx = Jd + "度" + Jf + "分" + Jm + "秒";
outy = Wd + "度" + Wf + "分" + Wm + "秒";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
6.拖動代碼
private void btnClearSelction_Click(object sender, EventArgs e)
{
ICommand pCommand = new ControlsMapIdentifyToolClass();
ITool pTool = pCommand as ITool;
switch (this.tabControl.SelectedTabIndex)
{
case 0:
pCommand.OnCreate(this.mainMapControl.Object);
this.mainMapControl.CurrentTool = pTool;
break;
case 1:
pCommand.OnCreate(this.axPageLayoutControl.Object);
this.axPageLayoutControl.CurrentTool = pTool;
break;
}
}
7.axMapControl和axPagelayoutControl數據同步顯示的程序 private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e) { axMapControl1.MousePointer = esriControlsMousePointer.esriPointerCrosshair; IGeometry pGeom = axMapControl1.TrackRectangle(); DrawMapShape(pGeom); axMapControl1.CtlRefresh(esriViewDrawPhase.esriViewGeography, null, null); } private void DrawMapShape(IGeometry pGeom) { IRgbColor pColor; pColor = new RgbColorClass(); pColor.Red =100; pColor.Green =100; pColor.Blue =100; ISimpleFillSymbol pFillsyl; pFillsyl = new SimpleFillSymbolClass();
pFillsyl.Color = pColor; object oFillsyl = pFillsyl; axMapControl1.DrawShape(pGeom, ref oFillsyl); } private void CopyAndOverwriteMap() { IObjectCopy objectCopy = new ObjectCopyClass(); object toCopyMap = axMapControl1.Map; object copiedMap = objectCopy.Copy(toCopyMap); object toOverwriteMap = axPageLayoutControl1.ActiveView.FocusMap; objectCopy.Overwrite(copiedMap, ref toOverwriteMap); } private void axMapControl1_OnAfterScreenDraw(object sender, IMapControlEvents2_OnAfterScreenDrawEvent e) { IActiveView activeView = (IActiveView)axPageLayoutControl1.ActiveView.FocusMap; IDisplayTransformation displayTransformation = activeView.ScreenDisplay.DisplayTransformation; displayTransformation.VisibleBounds = axMapControl1.Extent;
axPageLayoutControl1.ActiveView.Refresh(); CopyAndOverwriteMap(); } private void axPageLayoutControl1_OnViewRefreshed(object sender, IPageLayoutControlEvents_OnViewRefreshedEvent e) { axTOCControl1.CtlUpdate(); CopyAndOverwriteMap(); }
8.放大 縮小
放大
ICommand pCommand = new ControlsMapZoomInToolClass(); ITool pTool = pCommand as ITool; pCommand.OnCreate(this.axMapControl1.Object); this.axMapControl1.CurrentTool = pTool;
縮小
ICommand pCommand = new ControlsMapZoomOutToolClass(); ITool pTool = pCommand as ITool; pCommand.OnCreate(this.axMapControl1.Object); this.axMapControl1.CurrentTool = pTool;
9. 在arcsence中的各個控件的應用 類似的arcmap也一樣。
case "ZoomIn":
{
ICommand command = new ControlsSceneZoomInTool();//ControlsSceneZoomInToolClass();
command.OnCreate(this.axSceneControl1.Object);
this.axSceneControl1.CurrentTool = command as ESRI.ArcGIS.SystemUI.ITool;
}
break;
case "toolFly":
{
ICommand command = new ControlsSceneFlyToolClass();//ControlsSceneZoomInToolClass();
command.OnCreate(this.axSceneControl1.Object);
this.axSceneControl1.CurrentTool = command as ESRI.ArcGIS.SystemUI.ITool;
}
break;
case "toolSelectFeatures":
{
ICommand command = new ControlsSceneSelectFeaturesToolClass();//ControlsSceneZoomInToolClass();
command.OnCreate(this.axSceneControl1.Object);
this.axSceneControl1.CurrentTool = command as ESRI.ArcGIS.SystemUI.ITool;
}
break;
case "toolTargetZoom":
{
ICommand command = new ControlsSceneTargetZoomToolClass();//ControlsSceneZoomInToolClass();
command.OnCreate(this.axSceneControl1.Object);
this.axSceneControl1.CurrentTool = command as ESRI.ArcGIS.SystemUI.ITool;
}
break;
case "toolFullExtent":
{
ICommand command = new ControlsSceneFullExtentCommandClass();//ControlsSceneZoomInToolClass();
command.OnCreate(this.axSceneControl1.Object);
this.axSceneControl1.CurrentTool = command as ESRI.ArcGIS.SystemUI.ITool;
}
break;
case "ZoomOut":
{
ICommand command = new ControlsSceneZoomOutTool();
command.OnCreate(this.axSceneControl1.Object);
this.axSceneControl1.CurrentTool = command as ESRI.ArcGIS.SystemUI.ITool;
}
break;
case "Pan":
{
ICommand command = new ControlsScenePanTool();
command.OnCreate(this.axSceneControl1.Object);
this.axSceneControl1.CurrentTool = command as ESRI.ArcGIS.SystemUI.ITool;
}
break;
case "Navigate":
{
ICommand command = new ControlsSceneNavigateTool();
command.OnCreate(this.axSceneControl1.Object);
this.axSceneControl1.CurrentTool = command as ESRI.ArcGIS.SystemUI.ITool;
10.在C#中如何連接ACCESS數據庫
using System.Data.OleDb
public string myConnstring="Provider=Microsoft.Jet.OLEDB.4.0;
Data Source="+HttpContext.Current.Server.MapPath("data.mdb"); //data.mdb是你的數據庫名稱
OleDbConnection MyConnection;
MyConnection = new OleDbConnection(myConnstring);
strInsert=""; //strinsert是你的sql語句
OleDbCommand MyCommand = new OleDbCommand(strInsert,MyConnection);
MyConnection.Open();
MyCommand.ExecuteNonQuery();
MyConnection.Close();
11.創建文件(word) //創建文件夾 System.Object Nothing = System.Reflection.Missing.Value; Directory.CreateDirectory("c:/CNSI"); //創建文件所在目錄 string name = "CNSI_" + DateTime.Now.ToLongDateString() + ".doc"; object filename = "c://CNSI//" + name; //文件保存路徑
//創建Word文檔 Microsoft.Office.Interop.Word.Application WordApp = new Microsoft.Office.Interop.Word.ApplicationClass(); Microsoft.Office.Interop.Word.Document WordDoc = WordApp.Documents.Add(ref Nothing, ref Nothing, ref Nothing, ref Nothing); IQueryFilter pQueryFilter; pQueryFilter = pFeatureWorkspace;
保存文檔: string name = "y00"; object filename = "c://CNSI//" + name;//保存文件路徑。 object Nothing = System.Reflection.Missing.Value; //Microsoft.Office.Interop.Word.Application WordApp = new Microsoft.Office.Interop.Word.ApplicationClass(); Microsoft.Office.Interop.Word.Document WordDocs = WordApp.Documents.Add(ref Nothing, ref Nothing, ref Nothing, ref Nothing); WordDocs.Close(ref Nothing, ref Nothing, ref Nothing); WordApp.Quit(ref Nothing, ref Nothing, ref Nothing); WordDocs.SaveAs(ref filename, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing, ref Nothing);
//WordApp.Quit(ref Nothing, ref Nothing, ref Nothing); message = name + "文檔生成成功,以保存到C:CNSI下"; hy catch { message = "文件導出異常!"; } string path = "E:\\yxl\\tianjia\\database2.mdb"; IWorkspace iW = AccessWorkspaceFromPropertySet(path); IFeatureWorkspace pFeatureWorkspace = (IFeatureWorkspace)iW; ITable pTable = pFeatureWorkspace.OpenTable("database2");
12. C#操作Access數據庫的方法
//取得連接 public OleDbConnection getConn() { ConnectDatabase connstr=new ConnectDatabase(); string connStr=connstr.GetConnectionString(); OleDbConnection oledb=new OleDbConnection(connStr); return oledb; }
(1)采用OleDbCommand,OleDbDataReader訪問數據庫
1.查詢
public User getUserFromName(string Searchname) { User tempUser=new User(); try { OleDbConnection oleconn=getConn();//數據庫連接 string strSel="select * from MyUser where UserName='"+Searchname+"'";//查詢語句 OleDbCommand myCommand=new OleDbCommand(strSel,oleconn);//查詢命令 oleconn.Open();//打開數據庫連接 OleDbDataReader reader; reader=myCommand.ExecuteReader();//執行查詢命令,返回記錄集 if(reader.Read()) { tempUser.ID=(int)reader["UserID"]; tempUser.Name=reader["UserName"].ToString(); tempUser.Salary=(float)reader["UserSalary"]; tempUser.Password=reader["UserPassword"].ToString(); tempUser.Memo=reader["UserMemo"].ToString(); tempUser.Birthday=(DateTime)reader["UserBirthday"]; tempUser.Address=reader["UserAddress"].ToString(); } else
{ throw new Exception("沒有記錄"); } reader.Close();//關閉記錄集 oleconn.Close();//關閉連接
} catch(Exception e) { throw new Exception("打開數據庫出錯"+e.Message); } return tempUser; }
2.插入記錄
public void InsertUser(User insertuser) { try { OleDbConnection oleconn=getConn();//數據庫連接 oleconn.Open();//打開數據庫連接 string strSel="insert into [MyUser]([UserName],[UserPassword],
[UserSalary],[UserAddress],[UserBirthday],[UserMemo])"; //插入語句 strSel+=" values
('"+insertuser.Name+"','"+insertuser.Password+"',"+insertuser.Salary.ToSt
ring(); strSel+=",'"+insertuser.Address+"',#"+insertuser.Birthday.ToString()
+"#,'"+insertuser.Memo+"')"; OleDbCommand myCommand=new OleDbCommand(strSel,oleconn);//查詢命令 myCommand.ExecuteNonQuery(); oleconn.Close();//關閉連接
} catch(Exception e) { throw new Exception("打開數據庫出錯"+e.Message); } }
3.刪除記錄
public void DeleteUser(int m_id) { try { OleDbConnection oleconn=getConn(); oleconn.Open(); string strSel="Delete From [Myuser] where UserID="+m_id.ToString(); OleDbCommand myCommand=new OleDbCommand(strSel,oleconn); myCommand.ExecuteNonQuery(); oleconn.Close(); } catch(Exception e) { throw new Exception("刪除記錄出錯"+e.Message); } }
(2)采用OleDbDataAdapter,OleDbCommandBuilder,DataSet,DataTable,DataRow訪
問數據庫
添加記錄如下
public void InsertUserA(User insertUser) { using(OleDbConnection conn=getConn()) { OleDbDataAdapter adapter = new OleDbDataAdapter(); string queryString="Select * from MyUser order by UserID"; adapter.SelectCommand = new OleDbCommand(queryString, conn);
OleDbCommandBuilder builder = new OleDbCommandBuilder(adapter); // builder.QuotePrefix="["; // builder.QuoteSuffix="]"; conn.Open();
DataSet users = new DataSet(); adapter.Fill(users,"MyUser"); DataTable dt=new DataTable(); dt=users.Tables["MyUser"]; DataRow r=dt.NewRow(); r["UserName"]=insertUser.Name; r["UserPassword"]=insertUser.Password; r["UserAddress"]=insertUser.Address; r["UserSalary"]=insertUser.Salary; r["UserBirthday"]=insertUser.Birthday; r["UserMemo"]=insertUser.Memo; dt.Rows.Add(r); adapter.Update(users, "MyUser");
} }
需要注意字段不能和關鍵字相同,否則會出現Insert into出錯的提示。解決辦法在
前一篇
(3)采用參數化查詢的方式
public class AccessUtil { public AccessUtil() { } private string connString;
public string ConnString {
get { return connString; } set { connString = value; } } public AccessUtil(string connstr) { this.connString = connstr; } //帶參數的插入語句,返回值為id關鍵字的值,單條插入語句 public int ExecuteInsert(string SQL, OleDbParameter[]
parameters) { using(OleDbConnection conn=new OleDbConnection(connString)) { OleDbCommand cmd = new OleDbCommand(SQL, conn); try { conn.Open(); if (parameters!=null) { cmd.Parameters.AddRange(parameters); } cmd.ExecuteNonQuery(); cmd.CommandText = @"Select @@identity"; int value = Int32.Parse(cmd.ExecuteScalar().ToString
()); return value;
} catch (System.Exception e) { throw e; } } } //不帶參數的插入語句,返回值為關鍵字的值 public int ExecuteInsert(string SQL)
{ return ExecuteInsert(SQL, null); } //帶參數的插入、刪除、更新語句,返回受影響的記錄的個數 public int ExecuteNoQuery(string SQL, OleDbParameter[]
parameters) { using(OleDbConnection conn=new OleDbConnection(connString)) { conn.Open(); OleDbCommand cmd = new OleDbCommand(SQL, conn); try { if (parameters!=null) { cmd.Parameters.AddRange(parameters); } int rows=cmd.ExecuteNonQuery(); return rows; } catch (System.Exception e) { throw e; } } } //不帶參數的插入、刪除、更新語句,返回受影響的記錄的個數 public int ExecuteNoQuery(string SQL) { return ExecuteNoQuery(SQL, null); } //帶參數的查詢語句,返回所查詢到的記錄集 public DataSet ExecuteQuery(string SQL, OleDbParameter[]
parameters) { using(OleDbConnection conn=new OleDbConnection(connString)) {
DataSet ds = new DataSet(); try { conn.Open(); OleDbDataAdapter da = new OleDbDataAdapter(SQL,
conn); if (parameters != null) { da.SelectCommand.Parameters.AddRange(parameters); } da.Fill(ds, "ds"); } catch(System.Exception e) { throw e; } return ds; } } //不帶參數的查詢,返回所查詢到的記錄集 public DataSet ExecuteQuery(string SQL) { return ExecuteQuery(SQL, null); }
}
class ManageUser { //Access數據庫工具對象 AccessUtil accessutil = new AccessUtil
(ConnectDatabase.GetConnectionString()); public ArrayList GetAllUserArr()//獲得User表中的所有記錄,存儲進
ArrayList。 {
string SQL = "select * from MyUser order by ID"; DataSet ds=accessutil.ExecuteQuery(SQL);//返回的臨時表的名稱
為“ds” /* ArrayList arr = new ArrayList(); for (int i = 0; i < ds.Tables
["ds"].Rows.Count;i++ ) { arr.Add(DataRow2User(ds.Tables["ds"].Rows
)); }*/ ArrayList arr = DataTable2ArrayList(ds.Tables["ds"]); return arr; } public DataSet GetAllUserDataSet()//存儲成DataSet { string SQL = "select * from MyUser order by ID"; DataSet ds = accessutil.ExecuteQuery(SQL); return ds; } private User DataRow2User(DataRow dr)//將數據表中的一條記錄轉換為
一個User類的實例 { User user = new User(); user.ID = Int32.Parse(dr["ID"].ToString()); user.Name = dr["Name"].ToString(); user.Address = dr["Address"].ToString(); user.Birthday = Convert.ToDateTime(dr
["Birthday"].ToString()); user.Memo = dr["Memo"].ToString(); user.Salary =(float) Convert.ToDouble(dr
["Salary"].ToString()); user.Password = dr["Password"].ToString(); return user; } private ArrayList DataTable2ArrayList(DataTable dt)//將一個表中的
記錄轉化為ArrayList對象 { ArrayList tempArr = new ArrayList(); DataTableReader dr = new DataTableReader(dt); while(dr.Read()) { User user = new User(); user.ID = Int32.Parse(dr["ID"].ToString()); user.Name = dr["Name"].ToString(); user.Address = dr["Address"].ToString(); user.Birthday = Convert.ToDateTime(dr["Birthday"].ToString()); user.Memo = dr["Memo"].ToString(); user.Salary = (float)Convert.ToDouble(dr["Salary"].ToString
()); user.Password = dr["Password"].ToString(); tempArr.Add(user); } return tempArr; } public DataSet GetUserByName(string name) { String SQL = "Select * from MyUser where Name=?"; OleDbParameter[] parameter = new OleDbParameter[1]; parameter[0] = new OleDbParameter("@Name",
OleDbType.VarChar); parameter[0].Value = name; DataSet dt= accessutil.ExecuteQuery(SQL, parameter); return dt; }
public int InsertUser(User inUser) { String SQL = "insert into [MyUser]([Name],[Password],
[Salary],[Address],[Birthday],[Memo]) values(?,?,?,?,?,?)"; OleDbParameter[] parameters = new OleDbParameter[6]; parameters[0] = new OleDbParameter("@Name",
OleDbType.VarChar); parameters[0].Value = inUser.Name; parameters[1] = new OleDbParameter("@Password",
OleDbType.VarChar); parameters[1].Value = inUser.Password; parameters[2] = new OleDbParameter("@Salary",
OleDbType.Single); parameters[2].Value = inUser.Salary; parameters[3] = new OleDbParameter("@Address",
OleDbType.VarChar); parameters[3].Value = inUser.Address; parameters[4] = new OleDbParameter("@Birthday",
OleDbType.Date); parameters[4].Value = inUser.Birthday; parameters[5] = new OleDbParameter("@Memo",
OleDbType.VarChar); parameters[5].Value = inUser.Memo; return accessutil.ExecuteInsert(SQL, parameters); } public void DelUserById(int id) {
String SQL = "DELETE FROM [MyUser] where ID=?"; OleDbParameter[] parameters = new OleDbParameter[1]; parameters[0] = new OleDbParameter("@ID", OleDbType.Integer); parameters[0].Value = id;
accessutil.ExecuteNoQuery(SQL, parameters); } public void UpdateUser(User userupdate) { String SQL = "update [MyUser] Set [Name]=?,[Password]=?,
[Salary]=?,[Address]=?,[Birthday]=?,[Memo]=? where [ID]=?"; OleDbParameter[] parameters = new OleDbParameter[7]; parameters[0] = new OleDbParameter("@Name",
OleDbType.VarChar); parameters[0].Value = userupdate.Name; parameters[1] = new OleDbParameter("@Password",
OleDbType.VarChar); parameters[1].Value = userupdate.Password; parameters[2] = new OleDbParameter("@Salary",
OleDbType.Single); parameters[2].Value = userupdate.Salary; parameters[3] = new OleDbParameter("@Address",
OleDbType.VarChar); parameters[3].Value = userupdate.Address; parameters[4] = new OleDbParameter("@Birthday",
OleDbType.Date); parameters[4].Value = userupdate.Birthday; parameters[5] = new OleDbParameter("@Memo",
OleDbType.VarChar); parameters[5].Value = userupdate.Memo; parameters[6] = new OleDbParameter("@ID", OleDbType.Integer); parameters[6].Value = userupdate.ID; accessutil.ExecuteNoQuery(SQL, parameters); } }
13.加載cad代碼
private void AddCADRasterLayer(string sPath, string sName)
{
IWorkspaceFactory pCadWorkspaceFactory= new CadWorkspaceFactoryClass();
IWorkspace pWorkspace = pCadWorkspaceFactory.OpenFromFile(sPath,0);
ICadDrawingWorkspace pCadDrawingWorkspace = pWorkspace as ICadDrawingWorkspace;
ICadDrawingDataset pCadDataset; //'定義并獲得CAD文件的數據集
pCadDataset = pCadDrawingWorkspace.OpenCadDrawingDataset(sName);
ICadLayer pCadLayer; //'加入圖層到Map對象中去
pCadLayer = new CadLayerClass();
pCadLayer.CadDrawingDataset = pCadDataset;
axMapControl1.AddLayer(pCadLayer, 0);
axMapControl1.Refresh();
}
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog openFileDialog1 = new OpenFileDialog();
openFileDialog1.Filter = "所有文件|*.*";
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
AddCADRasterLayer(openFileDialog1.FileName,"11.dwg");//
}
}
您正在看的文章來自地信網論壇 http://bbs.3s001.com,原文地址:http://bbs.3s001.com/read.php?tid=8114.html
(七) 給PageLayoutControl添加彈出式菜單?
與給跟綁定控件協作的ToolbarControl增加ArcGIS Engine命令一樣,按照前面的步驟,你也可以從ArcGIS Engine命令創建彈出式菜單。下面將向你的應用程序中增加與PageLayoutControl協作的彈出式菜單。當在PageLayoutControl可視區域點擊鼠標右鍵的時候,彈出式菜單將顯示。
1.?????? 向類中添加如下的成員變量(紅色部分):
? public class Form1 : System.Windows.Forms.Form
? {
????? private ESRI.ArcGIS.MapControl.AxMapControl axMapControl1;
????? private ESRI.ArcGIS.PageLayoutControl.AxPageLayoutControl axPageLayoutControl1;
????? private ESRI.ArcGIS.TOCControl.AxTOCControl axTOCControl1;
????? private ESRI.ArcGIS.ToolbarControl.AxToolbarControl axToolbarControl1;
?
?? private IToolbarMenu m_ToolbarMenu = new ToolbarMenuClass(); // 彈出式菜單
// ……
2.?????? 在Form_Load事件中向ToolbarControl增加命令代碼的后面加載文檔代碼的前面增加如下代碼。
???? private void Form1_Load(object sender, System.EventArgs e)
???? {
???????? // 前面是增加地圖導航的代碼……
????????
// 共享ToolbarControl的命令池
???????? m_ToolbarMenu.CommandPool = axToolbarControl1.CommandPool;
?
???????? // 向ToolbarMenu增加命令
???????? progID = "esriControlToolsPageLayout.ControlsPageZoomInFixedCommand";
???????? m_ToolbarMenu.AddItem(progID, -1, -1, false,
???????????? esriCommandStyles.esriCommandStyleIconAndText);
?
???????? progID = "esriControlToolsPageLayout.ControlsPageZoomOutFixedCommand";
???????? m_ToolbarMenu.AddItem(progID, -1, -1, false,
???????????? esriCommandStyles.esriCommandStyleIconAndText);
?
???????? progID = "esriControlToolsPageLayout.ControlsPageZoomWholePageCommand";
???????? m_ToolbarMenu.AddItem(progID, -1, -1, false,
???????????? esriCommandStyles.esriCommandStyleIconAndText);
?
???????? progID = "esriControlToolsPageLayout.ControlsPageZoomPageToLastExtentBackCommand";
???????? m_ToolbarMenu.AddItem(progID, -1, -1, true,
???????????? esriCommandStyles.esriCommandStyleIconAndText);
?
???????? progID = "esriControlToolsPageLayout.ControlsPageZoomPageToLastExtentForwardCommand";
???????? m_ToolbarMenu.AddItem(progID, -1, -1, false,
???????????? esriCommandStyles.esriCommandStyleIconAndText);
?
???????? // 設置與PageLayoutControl掛接
?????? m_ToolbarMenu.SetHook(axPageLayoutControl1);
??????
??????????? // 后面是加載圖形文檔的代碼……
??????????? // ……
3.?????? 在設計模式顯示窗體并從屬性窗口中選擇axPageLayoutControl1,顯示axPageLayoutControl事件。雙擊OnMouseDown事件,向代碼窗口中增加事件處理代碼。
4.?????? 在axPageLayoutControl1_OnMouseDown事件中增加如下代碼:
???? private void axPageLayoutControl1_OnMouseDown(object sender, ESRI.ArcGIS.PageLayoutControl.IPageLayoutControlEvents_OnMouseDownEvent e)
???? {
???????? // 彈出ToolbarMenu
???????? if ( e.button == 2)
???????? {
???????????? m_ToolbarMenu.PopupMenu(e.x, e.y, axPageLayoutControl1.hWnd);
???????? }
}
5.???? 生成并運行應用程序。在PageLayoutControl的顯示區域單擊右鍵以顯示彈出菜單,并為頁面布局導航。
?
(八) 在TOCControl中控制標簽編輯?
TOCControl默認允許用戶自動地切換圖層的可見性并改變顯示在目錄表中的名稱。你可以增加代碼防止用戶在編輯名稱時輸入空的字符串。
1.?????? 在Form_Load事件的開始增加下列代碼。
???? private void Form1_Load(object sender, System.EventArgs e)
???? {
???????? // 當縮放時禁止重繪
???????? this.SetStyle(ControlStyles.EnableNotifyMessage, true);
?
???????? // 設置標簽編輯為手動方式
???????? axTOCControl1.LabelEdit = esriTOCControlEdit.esriTOCControlManual;
?
??????????? // 后面是加載文檔代碼
??????????? // ……
2.?????? 在設計模式顯示窗體并從屬性窗口選擇AxTOCControl1控件,顯示AxTOCControl事件。雙擊OnEndLabelEdit向代碼窗口添加事件處理函數。
3.???? 在axTOCControl1_OnEndLabelEdit事件中添加以下代碼:
???? private void axTOCControl1_OnEndLabelEdit(object sender, ESRI.ArcGIS.TOCControl.ITOCControlEvents_OnEndLabelEditEvent e)
???? {
???????? // 禁止在編輯標簽時鍵入空字串
???????? string newLabel = e.newLabel;
???????? if ( newLabel.Trim() == "" )
???????? {
???????????? e.canEdit = false;
???????? }
???? }
4.?????? 生成并生成應用程序。編輯TOCControl控件的地圖、圖層、標題或圖例類的標簽,在其上點擊一次,然后再點一次調用標簽編輯。試著用空字串替代標簽。在編輯期間,你可以隨時使用鍵盤上的ESC鍵取消編輯。
(九) 在MapControl上繪制圖形?
你可以將MapControl作為縮略圖窗體使用,并在其上繪制顯示PageLayoutControl內的焦點地圖的當前范圍。當你瀏覽PageLayoutControl數據框架內的數據時,你將看到縮略圖窗口也進行了更新。
注:使用地圖導航工具導航焦點圖(活動圖)將改變PageLayoutControl中焦點地圖的范圍并引起MapControl更新。使用頁面布局工具導航頁面布局將改變頁面布局的范圍(不是PageLayoutControl中的焦點圖的范圍),而MapControl將不更新。
1.?????? 向類中增加下列成員變量:
public class Form1 : System.Windows.Forms.Form
{
???? private ESRI.ArcGIS.MapControl.AxMapControl axMapControl1;
???? private ESRI.ArcGIS.PageLayoutControl.AxPageLayoutControl axPageLayoutControl1;
???? private ESRI.ArcGIS.TOCControl.AxTOCControl axTOCControl1;
???? private ESRI.ArcGIS.ToolbarControl.AxToolbarControl axToolbarControl1;
?
???? private IToolbarMenu m_ToolbarMenu = new ToolbarMenuClass(); // 彈出式菜單
?
???? private IEnvelope m_Envelope;?? // MapControl繪制的范圍
???? private Object m_FillSymbol;??? // 在MapControl上繪制范圍使用的符號
???? private ITransformEvents_VisibleBoundsUpdatedEventHandler
????????? visBoundsUpdatedE;????????? // PageLayoutControl的焦點圖事件
注:聲明的變量visBoundsUpdatedE是一個托管。托管是一個類,它能夠擁有對指定方法的引用,并使它鏈接到一個特定的事件。在事件和方法之間的鏈接過程有時在.NET中被稱作wiring。
2.?????? 創建一個叫CreateOverviewSymbol的新函數。這個函數是創建你將在MapControl中使用的符號的地方,此符號是用來描述PageLayoutControl焦點地圖數據范圍的。函數中增加的代碼如下:
private void CreateOverviewSymbol()
???? {
???????? // 獲取IRGBColor接口
???????? IRgbColor color = new RgbColor();
???????? // 設置顏色屬性
???????? color.RGB = 255;
?
???????? // 獲取ILine符號接口
???????? ILineSymbol outline = new SimpleLineSymbol();
???????? // 設置線符號屬性
???????? outline.Width = 1.5;
???????? outline.Color = color;
?
???????? // 獲取IFillSymbol接口
???????? ISimpleFillSymbol simpleFillSymbol = new SimpleFillSymbolClass();
???????? // 設置填充符號屬性
???????? simpleFillSymbol.Outline = outline;
???????? simpleFillSymbol.Style = esriSimpleFillStyle.esriSFSHollow;
???????? m_FillSymbol = simpleFillSymbol;???????????
}
3.?????? 從Form_Load事件在TOCControl標簽編輯代碼之前調用CreateOverviewSymbol函數。
???? private void Form1_Load(object sender, System.EventArgs e)
???? {
???????? // 當縮放時禁止重繪
???????? this.SetStyle(ControlStyles.EnableNotifyMessage, true);
?
???????? // 創建MapControl使用的符號
CreateOverviewSymbol();
?
// 下面是標簽編輯處理代碼
// ……
}
4.?????? 增加下列OnVisibleBoundsUpdated函數。此函數將與地圖范圍改變時觸發的事件相連接,并用來設置新的地圖可見邊界范圍框。通過刷新MapControl,你強制它重繪其上顯示的圖形。
???? private void OnVisibleBoundsUpdated(IDisplayTransformation sender, bool sizeChanged)
???? {
???????? // 設置新的可見范圍
???????? m_Envelope = sender.VisibleBounds;
?
???????? // 改變MapControl的前景狀態
axMapControl1.ActiveView.PartialRefresh(
esriViewDrawPhase,esriViewForeground, null, null);??????
}
5.?????? PageLayoutControl默認的事件接口是IPageLayoutControlEvents。這些事件不告訴我們數據邊框內的地圖范圍。為此你需要使用PageLayoutControl的焦點地圖的ItransformEvents接口。在PageLayoutControl_OnPageLayoutReplaced事件處理中的加載文檔代碼前面增加以下代碼。
private void axPageLayoutControl1_OnPageLayoutReplaced(object sender, ESRI.ArcGIS.PageLayoutControl.IPageLayoutControlEvents_OnPageLayoutReplacedEvent e)
???? {
???????? // 獲取PageLayoutControl中焦點地圖的IActiveView對象
???????? IActiveView activeView = (IActiveView)
???????????? axPageLayoutControl1.ActiveView.FocusMap;
?
???????? // 捕捉PageLayoutControl的焦點圖的ITransformEvents事件
???????? visBoundsUpdatedE = new ??????? ITransformEvents_VisibleBoundsUpdatedEventHandler(OnVisibleBoundsUpdated);
???????? ((ITransformEvents_Event)activeView.ScreenDisplay
???????????? .DisplayTransformation).VisibleBoundsUpdated += visBoundsUpdatedE;
????????
???????? // 獲取焦點圖的范圍
m_Envelope = activeView.Extent;
?
// 后面是加載地圖文檔的代碼
// ……
6.?????? 在設計模式下顯示窗體并從屬性窗中選擇axMapControl1,顯示axMapControl事件。雙擊OnAfterDraw向代碼窗口中增加事件處理。
7.?????? 向axMapControl1_OnAfterDraw事件處理中增加以下代碼,使用前面創建的符號繪制MapControl顯示邊框。
private void axMapControl1_OnAfterDraw(object sender, ESRI.ArcGIS.MapControl.IMapControlEvents2_OnAfterDrawEvent e)
???? {
???????? if ( m_Envelope == null)
???????? {
???????????? return;
???????? }
?
???????? // 如果前景狀態被重繪
???????? esriViewDrawPhase viewDrawPhase = (esriViewDrawPhase)e.viewDrawPhase;
???????? if ( viewDrawPhase == esriViewDrawPhase.esriViewForeground )
???????? {
???????????? IGeometry geometry = m_Envelope;
???????????? axMapControl1.DrawShape(geometry, ref m_FillSymbol);
???????? }
}
生成并運行應用程序。使用你先前已經加好的地圖導航工具改變PageLayoutControl中焦點地圖的范圍。新的范圍被繪制在MapControl上。
本講主要是使用MapControl、PageLayoutControl、ToolbarControl、TOCControl四個控件建立起基本的桌面GIS應用程序框架。最終成果預覽如下:
?
1、新建項目
啟動VS2005,選擇“文件|新建|項目”,在項目類型中選擇Visual C#,再選擇Windows應用程序模板,輸入名稱“3sdnMap”,點擊確定。
?
在解決方案管理器中將“Form1.cs”重命名為“3sdnMap.cs”,在設計視圖中,選中窗體,將其屬性中的“Text”改為“3sdnMap”。
2、添加控件
選擇工具箱中的“菜單和工具欄|MenuStrip”,將其拖入窗體。
選擇工具箱中的“ArcGIS Windows Forms”節,將“ToolbarControl”控件拖入窗體,并將其屬性中的Dock設置為Top。
選擇工具箱中的“菜單和工具欄|StatusStrip”,將其拖入到窗體。
選擇工具箱中的“容器|SplitContainer”容器拖入窗體,并將其屬性中的Dock設置為Fill。
將TabControl控件拖入Panel1,將Alignment屬性設置為Bottom,Dock屬性設置為Fill。點擊TabPages屬性右邊的按鈕,彈出TabPage集合編輯器,將tabPage1的Name設置為tabPageLayer,Text設置為圖層,將tabPage2的Name設置為tabPageProperty,Text設置為屬性。如下所示。
?
選擇“圖層”選項卡,拖入TOCControl控件,設置Dock屬性為Fill。
選擇“屬性”選項卡,拖入DataGridView控件,設置Dock屬性為Fill。
拖入TabControl控件到Panel2,設置Dock屬性為Fill。并上述類似的方法,將兩個選項卡的Name和Text分別設置為:(tabPageMap、地圖),(tabPageLayout,制版)。
選擇“地圖”選項卡,拖入MapControl控件,設置Dock屬性為Fill。
選擇“制版”選項卡,拖入PageLayoutControl控件,設置Dock屬性為Fill。
最后將LicenseControl控件拖入到窗體的任意地方。
按F5編譯運行,可以看到剛才布局好的程序界面了。
3、控件綁定
通過以上步驟添加的控件還只是單獨存在,而我們的程序需要各控件間協同工作,因此要進行控件綁定。
分別右擊ToolbarControl、TOCControl控件,將Buddy設置為axMapControl1,如下圖所示。
?
這樣,工具條和圖層控件就與地圖控件關聯了。
4、添加工具
此時,工具條中還沒有任何工具,添加的方法也很簡單。右擊ToolbarControl,選擇“屬性|Items”,點擊Add,選擇Commands選項卡中的Generic,雙擊Open、SaveAs、Redo、Undo即可將相應工具添加到工具條。
?
常見的工具有:
Map Navigation中的導航工具,Map Inquiry中的查詢工具,Feature Selection中的選擇工具,你可以根據需要酌情添加工具。
5、編譯運行
按F5即可編譯運行程序,至此桌面GIS應用程序框架基本框架已經搭建好了,你可以通過工具條的工具打開地圖文檔,瀏覽地圖了,效果如開篇所示.
在這一講中,主要講解菜單的添加和實現。
1、 添加菜單
在設計視圖中,單擊菜單欄,會出現“請在此處鍵入”的提示,單擊提示就可以鍵入菜單名稱,如“文件”,再單擊“文件”,即可輸入其下拉子菜單,如下所示:
Tips :
每創建一個菜單,請在其屬性面板中設置 Name 屬性,而且不要為中文,因此 Name 值將是此菜單響應函數的函數名的一部分,帶中文的函數名,總是不好吧。
本講中,我們將添加新建( New )、打開( Open )、添加數據( AddData )、保存( Save )、另存為( SaveAs )、退出( Exit )這些菜單,()內為相應的 Name 屬性值。
Tips:
你可以在屬性面板中的 Text 屬性中,把菜單名設置為中英文形式,如“打開 O pen ”,帶下劃線的 O 表示此項菜單的快捷鍵是字母 O ,設置方法是在相應字母前加上“ & ”字符,如“打開 &Open ”。但這種快捷鍵只在打開此下拉菜單時才有效,即當你單擊“文件”菜單彈出下拉菜單時,按下字母 O 就可以定位到“打開”菜單。
還有一種在程序運行時都有效的全局快捷鍵,可以在屬性面板中的“ ShortCutKeys ”中設置。
你還可以在屬性面板中的 Image 屬性中設置你喜歡的菜單圖標。單擊 Image 那一行右邊的按鈕,彈出如下菜單。選擇“項目資源文件”,再單擊導入就可以選擇你的圖標了。
最終效果如下所示。
注意,在解決方案面板中,選中剛才添加的所有圖標,在其屬性面板中將生成操作設置為“嵌入的資源”,這一點很重要!
2、 實現相關菜單
首先定義指針(寫在 public partial class Form1 : Form 下面即可):
| ?private ESRI.ArcGIS.Controls.IMapControl3 m_mapControl = null; private ESRI.ArcGIS.Controls.IPageLayoutControl2 m_pageLayoutControl = null; private IMapDocument pMapDocument; |
?若以上指針無效,請添加以下引用:
| using ESRI.ArcGIS.Carto; using ESRI.ArcGIS.Controls; using ESRI.ArcGIS.esriSystem; using ESRI.ArcGIS.Display; using ESRI.ArcGIS.Geometry; using ESRI.ArcGIS.SystemUI; |
在設計視圖中的屬性面板中,選擇 Form1 ,即主窗體,單擊事件按鈕(閃電形狀的那個按鈕),打到“ Load ”事件并雙擊,添加此事件。
在 Form1_Load 函數中初始化這些指針:
// 取得 MapControl 和 PageLayoutControl 的引用
| m_mapControl = (IMapControl3)this.axMapControl1.Object; m_pageLayoutControl = (IPageLayoutControl2)this.axPageLayoutControl1.Object; |
依次雙擊每個菜單項,添加菜單響應函數。實現代碼如下:
| /// <summary> /// 新建地圖命令 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void New_Click(object sender, EventArgs e) { // 本命令涉及到 MapControl 和 PageLayoutControl 同步問題,將在下一講中實現 } /// <summary> /// 打開地圖文檔 Mxd 命令 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Open_Click(object sender, EventArgs e) { // 本命令涉及到 MapControl 和 PageLayoutControl 同步問題,將在下一講中實現 } /// <summary> /// 添加數據命令 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void AddData_Click(object sender, EventArgs e) { int currentLayerCount = this.axMapControl1.LayerCount; ICommand pCommand = new ControlsAddDataCommandClass(); pCommand.OnCreate(this.axMapControl1.Object); pCommand.OnClick(); } /// <summary> /// 保存地圖文檔命令 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Save_Click(object sender, EventArgs e) { // 首先確認當前地圖文檔是否有效 if (null != m_pageLayoutControl.DocumentFilename && m_mapControl.CheckMxFile(m_pageLayoutControl.DocumentFilename)) { // 創建一個新的地圖文檔實例 IMapDocument mapDoc = new MapDocumentClass(); // 打開當前地圖文檔 mapDoc.Open(m_pageLayoutControl.DocumentFilename, string.Empty); // 用 PageLayout 中的文檔替換當前文檔中的 PageLayout 部分 mapDoc.ReplaceContents((IMxdContents)m_pageLayoutControl.PageLayout); // 保存地圖文檔 mapDoc.Save(mapDoc.UsesRelativePaths, false); mapDoc.Close(); } } /// <summary> /// 另存為地圖文檔命令 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void SaveAs_Click(object sender, EventArgs e) { // 調用另存為命令 ICommand command = new ControlsSaveAsDocCommandClass(); command.OnCreate(m_controlsSynchronizer.ActiveControl); command.OnClick(); } /// <summary> /// 退出程序 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Exit_Click(object sender, EventArgs e) { Application.Exit(); } |
3、 編譯運行
按 F5 編譯運行程序。也許你會發現,菜單命令的實現方式都是類型的。沒錯,在 AE9.2 中,內置了許多常用的 Command 和 Tool ,如 ControlsAddDataCommandClass 、 ControlsMapZoomInToolClass 、 ControlsMapPanToolClass 等等,這些內置對象在 ESRI.ArcGIS.Controls 命名空間中,你可以對象瀏覽器中查看。而且這些內置對象的調用方式都類似,如下所示:
| ?// 定義 |
希望你可以舉一反三,去實現更多的你想要的功能。
在ArcMap中,能夠很方面地進行MapView和Layout View兩種視圖的切換,而且二者之間的數據是同步顯示的。
關于兩種視圖同步的實現方法有多種,可以使用ObjectCopy對象進行數據硬拷貝,而比較簡單的方法莫過于二者共享一份地圖了,這也是最常用的方法。
1、新建同步類ControlsSynchronizer
在解決方案面板中右擊項目名,選擇“添加|類”,在類別中選擇“Visual C#項目項”,在模板中選擇“類”,輸入類名“ControlsSynchronizer.cs”,將以下代碼覆蓋自動生成的代碼:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.SystemUI;
namespace _sdnMap
{
??? /// <summary>
??? /// This class is used to synchronize a gven PageLayoutControl and a MapControl.
??? /// When initialized, the user must pass the reference of these control to the class, bind
??? /// the control together by calling 'BindControls' which in turn sets a joined Map referenced
??? /// by both control; and set all the buddy controls joined between these two controls.
??? /// When alternating between the MapControl and PageLayoutControl, you should activate the visible control
??? /// and deactivate the other by calling ActivateXXX.
??? /// This calss is limited to a situation where the controls are not simultaneously visible.
??? /// </summary>
??? public class ControlsSynchronizer
??? {
??????? #region class members
??????? private IMapControl3 m_mapControl = null;
??????? private IPageLayoutControl2 m_pageLayoutControl = null;
??????? private ITool m_mapActiveTool = null;
??????? private ITool m_pageLayoutActiveTool = null;
??????? private bool m_IsMapCtrlactive = true;
??????? private ArrayList m_frameworkControls = null;
??????? #endregion
??????? #region constructor
??????? /// <summary>
??????? /// 默認構造函數
??????? /// </summary>
??????? public ControlsSynchronizer()
??????? {
??????????? //初始化ArrayList
??????????? m_frameworkControls = new ArrayList();
??????? }
??????? /// <summary>
??????? /// 構造函數
??????? /// </summary>
??????? /// <param name="mapControl"></param>
??????? /// <param name="pageLayoutControl"></param>
??????? public ControlsSynchronizer(IMapControl3 mapControl, IPageLayoutControl2 pageLayoutControl)
??????????? : this()
??????? {
??????????? //為類成員賦值
??????????? m_mapControl = mapControl;
??????????? m_pageLayoutControl = pageLayoutControl;
??????? }
??????? #endregion
??????? #region properties
??????? /// <summary>
??????? /// 取得或設置MapControl
??????? /// </summary>
??????? public IMapControl3 MapControl
??????? {
??????????? get { return m_mapControl; }
??????????? set { m_mapControl = value; }
??????? }
??????? /// <summary>
??????? /// 取得或設置PageLayoutControl
??????? /// </summary>
??????? public IPageLayoutControl2 PageLayoutControl
??????? {
??????????? get { return m_pageLayoutControl; }
??????????? set { m_pageLayoutControl = value; }
??????? }
??????? /// <summary>
??????? /// 取得當前ActiveView的類型
??????? /// </summary>
??????? public string ActiveViewType
??????? {
??????????? get
??????????? {
??????????????? if (m_IsMapCtrlactive)
??????????????????? return "MapControl";
??????????????? else
??????????????????? return "PageLayoutControl";
??????????? }
??????? }
??????? /// <summary>
??????? /// 取得當前活動的Control
??????? /// </summary>
??????? public object ActiveControl
??????? {
??????????? get
??????????? {
??????????????? if (m_mapControl == null || m_pageLayoutControl == null)
??????????????????? throw new Exception("ControlsSynchronizer::ActiveControl:\r\nEither MapControl?or?PageLayoutControl are not initialized!");
??????????????? if (m_IsMapCtrlactive)
??????????????????? return m_mapControl.Object;
??????????????? else
??????????????????? return m_pageLayoutControl.Object;
??????????? }
??????? }
??????? #endregion
??????? #region Methods
??????? /// <summary>
??????? /// 激活MapControl并解除the PagleLayoutControl
??????? /// </summary>
??????? public void ActivateMap()
??????? {
??????????? try
??????????? {
??????????????? if (m_pageLayoutControl == null || m_mapControl == null)
??????????????????? throw new Exception("ControlsSynchronizer::ActivateMap:\r\nEither MapControl?or?PageLayoutControl are not initialized!");
??????????????? //緩存當前PageLayout的CurrentTool
??????????????? if (m_pageLayoutControl.CurrentTool != null) m_pageLayoutActiveTool = m_pageLayoutControl.CurrentTool;
??????????????? //解除PagleLayout
??????????????? m_pageLayoutControl.ActiveView.Deactivate();
?????????????? //激活MapControl
??????????????? m_mapControl.ActiveView.Activate(m_mapControl.hWnd);
??????????????? //將之前MapControl最后使用的tool,作為活動的tool,賦給MapControl的CurrentTool
??????????????? if (m_mapActiveTool != null) m_mapControl.CurrentTool = m_mapActiveTool;
??????????????? m_IsMapCtrlactive = true;
??????????????? //為每一個的framework controls,設置Buddy control為MapControl
??????????????? this.SetBuddies(m_mapControl.Object);
??????????? }
??????????? catch (Exception ex)
??????????? {
??????????????? throw new Exception(string.Format("ControlsSynchronizer::ActivateMap:\r\n{0}", ex.Message));
??????????? }
??????? }
??????? /// <summary>
??????? /// 激活PagleLayoutControl并減活MapCotrol
??????? /// </summary>
??????? public void ActivatePageLayout()
??????? {
??????????? try
??????????? {
??????????????? if (m_pageLayoutControl == null || m_mapControl == null)
??????????????????? throw new Exception("ControlsSynchronizer::ActivatePageLayout:\r\nEither MapControl?or?PageLayoutControl are not initialized!");
??????????????? //緩存當前MapControl的CurrentTool
??????????????? if (m_mapControl.CurrentTool != null) m_mapActiveTool = m_mapControl.CurrentTool;
??????????????? //解除MapControl
??????????????? m_mapControl.ActiveView.Deactivate();
??????????????? //激活PageLayoutControl
??????????????? m_pageLayoutControl.ActiveView.Activate(m_pageLayoutControl.hWnd);
??????????????? //將之前PageLayoutControl最后使用的tool,作為活動的tool,賦給PageLayoutControl的CurrentTool
??????????????? if (m_pageLayoutActiveTool != null) m_pageLayoutControl.CurrentTool = m_pageLayoutActiveTool;
??????????????? m_IsMapCtrlactive = false;
??????????????? //為每一個的framework controls,設置Buddy control為PageLayoutControl
??????????????? this.SetBuddies(m_pageLayoutControl.Object);
??????????? }
??????????? catch (Exception ex)
??????????? {
??????????????? throw new Exception(string.Format("ControlsSynchronizer::ActivatePageLayout:\r\n{0}", ex.Message));
??????????? }
??????? }
??????? /// <summary>
??????? /// 給予一個地圖, 置換PageLayoutControl和MapControl的focus map
??????? /// </summary>
??????? /// <param name="newMap"></param>
??????? public void ReplaceMap(IMap newMap)
??????? {
??????????? if (newMap == null)
??????????????? throw new Exception("ControlsSynchronizer::ReplaceMap:\r\nNew map for replacement is not initialized!");
??????????? if (m_pageLayoutControl == null || m_mapControl == null)
??????????????? throw new Exception("ControlsSynchronizer::ReplaceMap:\r\nEither MapControl?or?PageLayoutControl are not initialized!");
??????????? //create a new instance of IMaps collection which is needed by the PageLayout
??????????? //創建一個PageLayout需要用到的,新的IMaps collection的實例
??????????? IMaps maps = new Maps();
??????????? //add the new map to the Maps collection
??????????? //把新的地圖加到Maps collection里頭去
??????????? maps.Add(newMap);
??????????? bool bIsMapActive = m_IsMapCtrlactive;
??????????? //call replace map on the PageLayout in order to replace the focus map
??????????? //we must call ActivatePageLayout, since it is the control we call 'ReplaceMaps'
??????????? //調用PageLayout的replace map來置換focus map
??????????? //我們必須調用ActivatePageLayout,因為它是那個我們可以調用"ReplaceMaps"的Control
??????????? this.ActivatePageLayout();
??????????? m_pageLayoutControl.PageLayout.ReplaceMaps(maps);
??????????? //assign the new map to the MapControl
??????????? //把新的地圖賦給MapControl
??????????? m_mapControl.Map = newMap;
??????????? //reset the active tools
??????????? //重設active tools
??????????? m_pageLayoutActiveTool = null;
??????????? m_mapActiveTool = null;
??????????? //make sure that the last active control is activated
??????????? //確認之前活動的control被激活
??????????? if (bIsMapActive)
??????????? {
??????????????? this.ActivateMap();
??????????????? m_mapControl.ActiveView.Refresh();
??????????? }
??????????? else
??????????? {
??????????????? this.ActivatePageLayout();
??????????????? m_pageLayoutControl.ActiveView.Refresh();
??????????? }
??????? }
??????? /// <summary>
??????? /// bind the MapControl and PageLayoutControl together by assigning a new joint focus map
??????? /// 指定共同的Map來把MapControl和PageLayoutControl綁在一起
??????? /// </summary>
??????? /// <param name="mapControl"></param>
??????? /// <param name="pageLayoutControl"></param>
??????? /// <param name="activateMapFirst">true if the MapControl supposed to be activated first,如果MapControl被首先激活,則為true</param>
??????? public void BindControls(IMapControl3 mapControl, IPageLayoutControl2 pageLayoutControl, bool activateMapFirst)
??????? {
??????????? if (mapControl == null || pageLayoutControl == null)
??????????????? throw new Exception("ControlsSynchronizer::BindControls:\r\nEither MapControl?or?PageLayoutControl are not initialized!");
??????????? m_mapControl = MapControl;
??????????? m_pageLayoutControl = pageLayoutControl;
??????????? this.BindControls(activateMapFirst);
??????? }
??????? /// <summary>
??????? /// bind the MapControl and PageLayoutControl together by assigning a new joint focus map
??????? /// 指定共同的Map來把MapControl和PageLayoutControl綁在一起
??????? /// </summary>
??????? /// <param name="activateMapFirst">true if the MapControl supposed to be activated first,如果MapControl被首先激活,則為true</param>
??????? public void BindControls(bool activateMapFirst)
??????? {
??????????? if (m_pageLayoutControl == null || m_mapControl == null)
??????????????? throw new Exception("ControlsSynchronizer::BindControls:\r\nEither MapControl?or?PageLayoutControl are not initialized!");
??????????? //create a new instance of IMap
??????????? //創造IMap的一個實例
??????????? IMap newMap = new MapClass();
??????????? newMap.Name = "Map";
??????????? //create a new instance of IMaps collection which is needed by the PageLayout
??????????? //創造一個新的IMaps collection的實例,這是PageLayout所需要的
??????????? IMaps maps = new Maps();
??????????? //add the new Map instance to the Maps collection
??????????? //把新的Map實例賦給Maps collection
??????????? maps.Add(newMap);
??????????? //call replace map on the PageLayout in order to replace the focus map
??????????? //調用PageLayout的replace map來置換focus map
??????????? m_pageLayoutControl.PageLayout.ReplaceMaps(maps);
??????????? //assign the new map to the MapControl
??????????? //把新的map賦給MapControl
??????????? m_mapControl.Map = newMap;
??????????? //reset the active tools
??????????? //重設active tools
??????????? m_pageLayoutActiveTool = null;
??????????? m_mapActiveTool = null;
??????????? //make sure that the last active control is activated
??????????? //確定最后活動的control被激活
??????????? if (activateMapFirst)
??????????????? this.ActivateMap();
??????????? else
??????????????? this.ActivatePageLayout();
??????? }
??????? /// <summary>
??????? ///by passing the application's toolbars and TOC to the synchronization class, it saves you the
??????? ///management of the buddy control each time the active control changes. This method ads the framework
??????? ///control to an array; once the active control changes, the class iterates through the array and
??????? ///calles SetBuddyControl on each of the stored framework control.
??????? /// </summary>
??????? /// <param name="control"></param>
??????? public void AddFrameworkControl(object control)
??????? {
??????????? if (control == null)
??????????????? throw new Exception("ControlsSynchronizer::AddFrameworkControl:\r\nAdded control is not initialized!");
??????????? m_frameworkControls.Add(control);
??????? }
??????? /// <summary>
??????? /// Remove a framework control from the managed list of controls
??????? /// </summary>
??????? /// <param name="control"></param>
??????? public void RemoveFrameworkControl(object control)
??????? {
??????????? if (control == null)
??????????????? throw new Exception("ControlsSynchronizer::RemoveFrameworkControl:\r\nControl to be removed is not initialized!");
??????????? m_frameworkControls.Remove(control);
??????? }
??????? /// <summary>
??????? /// Remove a framework control from the managed list of controls by specifying its index in the list
??????? /// </summary>
??????? /// <param name="index"></param>
??????? public void RemoveFrameworkControlAt(int index)
??????? {
??????????? if (m_frameworkControls.Count < index)
??????????????? throw new Exception("ControlsSynchronizer::RemoveFrameworkControlAt:\r\nIndex is out of range!");
??????????? m_frameworkControls.RemoveAt(index);
??????? }
??????? /// <summary>
??????? /// when the active control changes, the class iterates through the array of the framework controls
??????? ///? and calles SetBuddyControl on each of the controls.
??????? /// </summary>
??????? /// <param name="buddy">the active control</param>
??????? private void SetBuddies(object buddy)
??????? {
??????????? try
??????????? {
??????????????? if (buddy == null)
??????????????????? throw new Exception("ControlsSynchronizer::SetBuddies:\r\nTarget Buddy Control is not initialized!");
??????????????? foreach (object obj in m_frameworkControls)
??????????????? {
??????????????????? if (obj is IToolbarControl)
??????????????????? {
??????????????????????? ((IToolbarControl)obj).SetBuddyControl(buddy);
??????????????????? }
??????????????????? else if (obj is ITOCControl)
??????????????????? {
??????????????????????? ((ITOCControl)obj).SetBuddyControl(buddy);
??????????????????? }
??????????????? }
??????????? }
??????????? catch (Exception ex)
??????????? {
??????????????? throw new Exception(string.Format("ControlsSynchronizer::SetBuddies:\r\n{0}", ex.Message));
??????????? }
??????? }
??????? #endregion
??? }
}
2、新建Maps類
在同步類中,要用到Maps類,用于管理地圖對象。與新建同步類ControlsSynchronizer類似,我們新建一Maps類,其所有代碼如下所示:
?using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using ESRI.ArcGIS.Carto;
namespace _sdnMap
{
??? [Guid("f27d8789-fbbc-4801-be78-0e3cd8fff9d5")]
??? [ClassInterface(ClassInterfaceType.None)]
??? [ProgId("_sdnMap.Maps")]
??? public class Maps : IMaps, IDisposable
??? {
??????? //class member - using internally an ArrayList to manage the Maps collection
??????? private ArrayList m_array = null;
??????? #region class constructor
??????? public Maps()
??????? {
??????????? m_array = new ArrayList();
??????? }
??????? #endregion
??????? #region IDisposable Members
??????? /// <summary>
???? ???/// Dispose the collection
??????? /// </summary>
??????? public void Dispose()
??????? {
??????????? if (m_array != null)
??????????? {
??????????????? m_array.Clear();
??????????????? m_array = null;
??????????? }
??????? }
??????? #endregion
????? ??#region IMaps Members
??????? /// <summary>
??????? /// Remove the Map at the given index
??????? /// </summary>
??????? /// <param name="Index"></param>
??????? public void RemoveAt(int Index)
??????? {
??????????? if (Index > m_array.Count || Index < 0)
??????????????? throw new Exception("Maps::RemoveAt:\r\nIndex is out of range!");
??????????? m_array.RemoveAt(Index);
??????? }
??????? /// <summary>
??????? /// Reset the Maps array
??????? /// </summary>
??????? public void Reset()
??????? {
????? ??????m_array.Clear();
??????? }
??????? /// <summary>
??????? /// Get the number of Maps in the collection
??????? /// </summary>
??????? public int Count
??????? {
??????????? get
??????????? {
??????????????? return m_array.Count;
??????????? }
?????? ?}
??????? /// <summary>
??????? /// Return the Map at the given index
??????? /// </summary>
??????? /// <param name="Index"></param>
??????? /// <returns></returns>
??????? public IMap get_Item(int Index)
??????? {
??????????? if (Index > m_array.Count || Index < 0)
??????????????? throw new Exception("Maps::get_Item:\r\nIndex is out of range!");
??????????? return m_array[Index] as IMap;
??????? }
??????? /// <summary>
??????? /// Remove the instance of the given Map
??????? /// </summary>
??????? /// <param name="Map"></param>
??????? public void Remove(IMap Map)
??????? {
??????????? m_array.Remove(Map);
??????? }
??????? /// <summary>
??????? /// Create a new Map, add it to the collection and return it to the caller
??????? /// </summary>
??????? /// <returns></returns>
??????? public IMap Create()
??????? {
??????????? IMap newMap = new MapClass();
??????????? m_array.Add(newMap);
??????????? return newMap;
??????? }
??????? /// <summary>
??????? /// Add the given Map to the collection
??????? /// </summary>
??????? /// <param name="Map"></param>
??????? public void Add(IMap Map)
??????? {
??????????? if (Map == null)
??????????????? throw new Exception("Maps::Add:\r\nNew Map is mot initialized!");
??????????? m_array.Add(Map);
??????? }
?????? ?#endregion
??? }
}
3、新建打開文檔類OpenNewMapDocument
由于從工具欄自帶的打開按鈕打開地圖文檔的時候,不會自動進行兩種視圖之間的同步,所以我們要自己派生一個OpenNewMapDocument類,用于打開地圖文檔。
?右擊項目名,選擇“添加|類”,再選擇ArcGIS類別中的BaseCommand模板,輸入類名為“OpenNewMapDocument.cs”。
首先添加引用:
using System.Windows.Forms;
using ESRI.ArcGIS.Carto;
再添加如下成員變量:
?private ControlsSynchronizer m_controlsSynchronizer = null;
修改默認的構造函數如下所示:
?//添加參數
public OpenNewMapDocument(ControlsSynchronizer controlsSynchronizer)
??????? {
??????????? //
??????????? // TODO: Define values for the public properties
???????? ???//
//設定相關屬性值
??????????? base.m_category = "Generic"; //localizable text
??????????? base.m_caption = "Open";? //localizable text
??????????? base.m_message = "This should work in ArcMap/MapControl/PageLayoutControl";? //localizable text
??????????? base.m_toolTip = "Open";? //localizable text
??????????? base.m_name = "Generic_Open";?? //unique id, non-localizable (e.g. "MyCategory_MyCommand")
???????????
?? //初始化m_controlsSynchronizer
??????????? m_controlsSynchronizer = controlsSynchronizer;
????? ??????try
??????????? {
??????????????? //
??????????????? // TODO: change bitmap name if necessary
??????????????? //
??????????????? string bitmapResourceName = GetType().Name + ".bmp";
??????????????? base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);
??????????? }
??????????? catch (Exception ex)
??????????? {
??????????????? System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
??????????? }
??????? }
再在OnClick函數中添加如下代碼:
?public override void OnClick()
??????? {
??????????? // TODO: Add OpenNewMapDocument.OnClick implementation
??????????? OpenFileDialog dlg = new OpenFileDialog();
??????????? dlg.Filter = "Map Documents (*.mxd)|*.mxd";
??????????? dlg.Multiselect = false;
??????????? dlg.Title = "Open Map Document";
??????????? if (dlg.ShowDialog() == DialogResult.OK)
??????????? {
??????????????? string docName = dlg.FileName;
??????????????? IMapDocument mapDoc = new MapDocumentClass();
??????????? ????if (mapDoc.get_IsPresent(docName) && !mapDoc.get_IsPasswordProtected(docName))
??????????????? {
??????????????????? mapDoc.Open(docName, string.Empty);
??????????????????? IMap map = mapDoc.get_Map(0);
??????????????????? m_controlsSynchronizer.ReplaceMap(map);
??????????????????? mapDoc.Close();
??????????????? }
??????????? }
??????? }
在添加類時,模板會自動添加一個名為“OpenNewMapDocument.bmp”的圖標,你可以自己修改或者替換為打開的文件夾的圖標。
4、兩種視圖的同步
在3sdnMap.cs中添加成員變量,即同步類對象:
?private ControlsSynchronizer m_controlsSynchronizer = null;
在Form1_Load函數中進行初始化工作:
?//初始化controls synchronization calss
m_controlsSynchronizer = new
ControlsSynchronizer(m_mapControl, m_pageLayoutControl);
???? //把MapControl和PageLayoutControl綁定起來(兩個都指向同一個Map),然后設置MapControl為活動的Control
???? m_controlsSynchronizer.BindControls(true);
???? //為了在切換MapControl和PageLayoutControl視圖同步,要添加Framework Control
??? m_controlsSynchronizer.AddFrameworkControl(axToolbarControl1.Object);
??? m_controlsSynchronizer.AddFrameworkControl(this.axTOCControl1.Object);
// 添加打開命令按鈕到工具條
OpenNewMapDocument openMapDoc = new OpenNewMapDocument(m_controlsSynchronizer);
axToolbarControl1.AddItem(openMapDoc, -1, 0, false, -1, esriCommandStyles.esriCommandStyleIconOnly);
因為我們自動派生了打開文檔類,并自己將其添加到工具條,所以我們就不需要工具條原來的“打開”按鈕了,可以ToolbarControl的屬性中將其刪除。
下面,我們可完成上一講遺留的功能了。
?/// <summary>
??????? /// 新建地圖命令
??????? /// </summary>
??????? /// <param name="sender"></param>
??????? /// <param name="e"></param>
??????? private void New_Click(object sender, EventArgs e)
??????? {
??????????? //詢問是否保存當前地圖
??????????? DialogResult res = MessageBox.Show("是否保存當前地圖?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
??????????? if (res == DialogResult.Yes)
??????????? {
??????????????? //如果要保存,調用另存為對話框
??????????????? ICommand command = new ControlsSaveAsDocCommandClass();
??????????????? if (m_mapControl != null)
??????????????????? command.OnCreate(m_controlsSynchronizer.MapControl.Object);
??????????????? else
??????????????????? command.OnCreate(m_controlsSynchronizer.PageLayoutControl.Object);
??????????????? command.OnClick();
??????????? }
???? //創建新的地圖實例
??????????? IMap map = new MapClass();
??????????? map.Name = "Map";
??????????? m_controlsSynchronizer.MapControl.DocumentFilename = string.Empty;
??????????? //更新新建地圖實例的共享地圖文檔
??????????? m_controlsSynchronizer.ReplaceMap(map);
??????? }
/// <summary>
??????? /// 打開地圖文檔Mxd命令
??????? /// </summary>
??????? /// <param name="sender"></param>
??????? /// <param name="e"></param>
??????? private void Open_Click(object sender, EventArgs e)
??????? {
if (this.axMapControl1.LayerCount > 0)
?? ?????????{
??????????????? DialogResult result = MessageBox.Show("是否保存當前地圖?", "警告",
MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question);
??????????????? if (result == DialogResult.Cancel) return;
??????????????? if (result == DialogResult.Yes) this.Save_Click(null, null);
??????????? }
??????????? OpenNewMapDocument openMapDoc =
new OpenNewMapDocument(m_controlsSynchronizer);
??????????? openMapDoc.OnCreate(m_controlsSynchronizer.MapControl.Object);
??????????? openMapDoc.OnClick();
}
在添加數據AddData時,我們也要進行地圖共享,故在AddData_Click函數后面添加如下代碼:
?IMap pMap = this.axMapControl1.Map;
this.m_controlsSynchronizer.ReplaceMap(pMap);
在另存為地圖文檔時,有可能會丟失數據,因此我們需要提示用戶以確認操作,故需修改SaveAs_Click函數,如下所示:
?/// <summary>
??????? /// 另存為地圖文檔命令
??????? /// </summary>
?????? ?/// <param name="sender"></param>
??????? /// <param name="e"></param>
??????? private void SaveAs_Click(object sender, EventArgs e)
??????? {
??????????? //如果當前視圖為MapControl時,提示用戶另存為操作將丟失PageLayoutControl中的設置
??????????? if (m_controlsSynchronizer.ActiveControl is IMapControl3)
??????????? {
??????????????? if (MessageBox.Show("另存為地圖文檔將丟失制版視圖的設置\r\n您要繼續嗎?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
??????????????????? return;
??????????? }
??????????? //調用另存為命令
???????? ???ICommand command = new ControlsSaveAsDocCommandClass();
??????????? command.OnCreate(m_controlsSynchronizer.ActiveControl);
??????????? command.OnClick();
??????? }
在切換視圖時,我們要激活相關的視圖,故在設計視圖的屬性面板中選擇tabControl2控件,再選擇事件按鈕,找到“SelectedIndexChanged”事件雙擊添加之。其實現代碼如下所示:
?/// <summary>
??????? /// 切換地圖和制版視圖
??????? /// </summary>
??????? /// <param name="sender"></param>
??????? /// <param name="e"></param>
??????? private void tabControl2_SelectedIndexChanged(object sender, EventArgs e)
??????? {
?????????? ?if (this.tabControl2.SelectedIndex == 0)
??????????? {
??????????????? //激活MapControl
??????????????? m_controlsSynchronizer.ActivateMap();
??????????? }
??????????? else
??????????? {
??????????????? //激活PageLayoutControl
??????????????? m_controlsSynchronizer.ActivatePageLayout();
??????????? }
??????? }
5、編譯運行
按F5編譯運行程序,至此我們完成了MapControl和PageLayoutControl兩種視圖的同步工作。
1、 添加狀態欄項目
在設計視圖中,點擊窗體中的狀態欄,在其屬性面板中找到“ Items ”項,單擊其右邊的按鈕,在下拉框中選擇“ StatusLabel ”,單擊“添加按鈕”,依次添加四個 StatusLabel ,依次修改屬性參數如下表所示:
序號
?Name 屬性
?Text 屬性
?Spring 屬性
?說明
1
?MessageLabel
?就緒
?False
?當前所用工具信息
2
?Blank
? True
?占位
3
?ScaleLabel
?比例尺
?False
?當前比例尺
4
?CoordinateLabel
?當前坐標
?False
?當前坐標
設置好之后如下圖所示:
Tips :
我們設計出的狀態欄最終如下所示:
就緒
?( Blank )
?比例尺
?當前坐標
Spring 屬性表示可以按狀態欄剩余空間自動伸縮。所以加入 Blank 項目,只是為了占個位子,以達到 ScaleLabel 和 CoordinateLabel 項目右對齊而 MessageLabel 項目左對齊的目的。
2、 顯示當前所用工具信息
首先添加 axToolbarControl1 的 OnMouseMove 事件 ( 相信大家看了以上的教程,已經知道怎么添加事件了吧,還不知道的建議再溫習下前幾講的內容 ) 。在其事件響應函數代碼如下:
?private void axToolbarControl1_OnMouseMove(object sender, IToolbarControlEvents_OnMouseMoveEvent e)
{
// 取得鼠標所在工具的索引號
int index = axToolbarControl1.HitTest(e.x, e.y, false);
if (index != -1)
{
// 取得鼠標所在工具的 ToolbarItem
IToolbarItem toolbarItem = axToolbarControl1.GetItem(index);
// 設置狀態欄信息
MessageLabel.Text = toolbarItem.Command.Message;
}
else
{
MessageLabel.Text = " 就緒 ";
}
}
3、 顯示當前比例尺
添加 axMapControl1 的 OnMouseMove 事件,其代碼如下:
?private void axMapControl1_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
{
// 顯示當前比例尺
ScaleLabel.Text = " 比例尺 1:" + ((long)this.axMapControl1.MapScale).ToString();
}
4、 顯示當前坐標
顯示當前坐標也是 axMapControl1 的 OnMouseMove 事件中響應,故只要在 axMapControl1_OnMouseMove 函數中添加如下代碼即可:
?// 顯示當前坐標
CoordinateLabel.Text = " 當前坐標 X = " + e.mapX.ToString() + " Y = " + e.mapY.ToString() + " " + this.axMapControl1.MapUnits;
按 F5 編譯運行,可以看到,我們的程序已經能夠正常工作了。但是細心的你可能會發現,當前坐標的后面的坐標單位為“ esriUnknownUnits ”或“ esriMeters ”之類,即系統在正常單位的前面加上了“ esri ”,追求完美的我們自然看得不舒服。那就進行簡單的替換吧。
首先定義個全局坐標單位變量 sMapUnits ,如下所示:
?private string sMapUnits;?
再 Form1_Load 函數中進行初始化:
sMapUnits = "Unknown";??
添加 axMapControl1 控件的 OnMapReplaced 事件,在事件響應函數中進行坐標單位替換,代碼如下:
?private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
{
esriUnits mapUnits = axMapControl1.MapUnits;
switch (mapUnits)
{
case esriUnits.esriCentimeters:
sMapUnits = "Centimeters";
break;
case esriUnits.esriDecimalDegrees:
sMapUnits = "Decimal Degrees";
break;
case esriUnits.esriDecimeters:
sMapUnits = "Decimeters";
break;
case esriUnits.esriFeet:
sMapUnits = "Feet";
break;
case esriUnits.esriInches:
sMapUnits = "Inches";
break;
case esriUnits.esriKilometers:
sMapUnits = "Kilometers";
break;
case esriUnits.esriMeters:
sMapUnits = "Meters";
break;
case esriUnits.esriMiles:
sMapUnits = "Miles";
break;
case esriUnits.esriMillimeters:
sMapUnits = "Millimeters";
break;
case esriUnits.esriNauticalMiles:
sMapUnits = "NauticalMiles";
break;
case esriUnits.esriPoints:
sMapUnits = "Points";
break;
case esriUnits.esriUnknownUnits:
sMapUnits = "Unknown";
break;
case esriUnits.esriYards:
sMapUnits = "Yards";
break;
}
}
5、 編譯運行
按 F5 編譯運行程序。如果你足夠細心的話,相信你已經成功了!
在本講中,介紹中 StatusStrip 控件的基本使用方法和 AE 中當所用工具信息、當前比例尺和當前坐標的顯示調用方法。
所謂的鷹眼,就是一個縮略地圖,上面有一個矩形框,矩形框區域就是當前顯示的地圖區域,拖動矩形框可以改變當前地圖顯示的位置,改變矩形框的大小,可以改變當前地圖的顯示區域大小,從起到導航的作用。鷹眼是地圖瀏覽中常用的功能之一。
關于鷹眼的實現方式,最常用的是用一個 MapControl 控件顯示地圖全圖,并在上面畫一個紅色矩形框表示當前地圖的顯示范圍,并實現鷹眼 MapControl 與主窗體的 MapControl 互動。本講最終效果如下所示:
圖 1 鷹眼效果
1 、添加鷹眼控件
由于本教程在第一講中沒有預先考慮到鷹眼所放的位置,故我們要先稍微調整一下程序框架,并添加一個 MapControl 用于顯示鷹眼。
在本教程中,我們將鷹眼放在圖層控件的下方,調整方法如下:
( 1 )在設計視圖中,選擇 tabControl1 控件,即放圖層和屬性的那個容器,將其 Dock 屬性設為 None ,并用鼠標拖拽將其縮小。把工具箱中的 SplitContainer 控件拖到窗體的左窗格,即放在 tabControl1 控件的旁邊。并將其 Orientation 屬性設置為 Horizontal 。
( 2 )選中 tabControl1 控件,按 Ctrl+X 剪切,再選中剛才粘貼到 SplitContainer2 的 Panel1 中,如圖 2 所示。操作完成后效果如圖 3 所示。
圖 2
圖 3
( 3 )再選中 SplitContainer2 控件(如果不好選中,直接以屬性面板中選擇 SplitContainer2 ),將其 Dock 屬性設置為 Fill 。再選中 tabControl1 ,將其 Dock 屬性也設置為 Fill 。
( 4 )從工具箱中選擇 MapControl 控件并拖到 SplitContainer2 的 Panel2 ,作為鷹眼控件。最終效果如圖 4 所示。
圖 4
2 、鷹眼的實現
( 1 )載入地圖到鷹眼控件
當地圖載入到主 Map 控件時,同時也載入到鷹眼控件,在 axMapControl1_OnMapReplaced 事件響應函數(此函數上一講中已經添加了)中添加如下代碼:
private void axMapControl1_OnMapReplaced(object sender, IMapControlEvents2_OnMapReplacedEvent e)
{
// 前面代碼省略
// 當主地圖顯示控件的地圖更換時,鷹眼中的地圖也跟隨更換
this.axMapControl2.Map = new MapClass();
// 添加主地圖控件中的所有圖層到鷹眼控件中
for (int i = 1; i <= this.axMapControl1.LayerCount; i++)
{
this.axMapControl2.AddLayer(this.axMapControl1.get_Layer(this.axMapControl1.LayerCount - i));
}
// 設置 MapControl 顯示范圍至數據的全局范圍
this.axMapControl2.Extent = this.axMapControl1.FullExtent;
// 刷新鷹眼控件地圖
this.axMapControl2.Refresh();
}
( 2 )繪制鷹眼矩形框
為鷹眼控件 MapControl1 添加 OnExtentUpdated 事件,此事件是在主 Map 控件的顯示范圍改變時響應,從而相應更新鷹眼控件中的矩形框。其響應函數代碼如下:
private void axMapControl1_OnExtentUpdated(object sender, IMapControlEvents2_OnExtentUpdatedEvent e)
{
// 得到新范圍
IEnvelope pEnv = (IEnvelope)e.newEnvelope;
IGraphicsContainer pGra = axMapControl2.Map as IGraphicsContainer;
IActiveView pAv = pGra as IActiveView;
// 在繪制前,清除 axMapControl2 中的任何圖形元素
pGra.DeleteAllElements();
IRectangleElement pRectangleEle = new RectangleElementClass();
IElement pEle = pRectangleEle as IElement;
pEle.Geometry = pEnv;
// 設置鷹眼圖中的紅線框
IRgbColor pColor = new RgbColorClass();
pColor.Red = 255;
pColor.Green = 0;
pColor.Blue = 0;
pColor.Transparency = 255;
// 產生一個線符號對象
ILineSymbol pOutline = new SimpleLineSymbolClass();
pOutline.Width = 2;
pOutline.Color = pColor;
// 設置顏色屬性
pColor = new RgbColorClass();
pColor.Red = 255;
pColor.Green = 0;
pColor.Blue = 0;
pColor.Transparency = 0;
// 設置填充符號的屬性
IFillSymbol pFillSymbol = new SimpleFillSymbolClass();
pFillSymbol.Color = pColor;
pFillSymbol.Outline = pOutline;
IFillShapeElement pFillShapeEle = pEle as IFillShapeElement;
pFillShapeEle.Symbol = pFillSymbol;
pGra.AddElement((IElement)pFillShapeEle, 0);
// 刷新
pAv.PartialRefresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
( 3 )鷹眼與主 Map 控件互動
為鷹眼控件 MapControl2 添加 OnMouseDown 事件,代碼如下:
private void axMapControl2_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
{
if (this.axMapControl2.Map.LayerCount != 0)
{
// 按下鼠標左鍵移動矩形框
if (e.button == 1)
{
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
IEnvelope pEnvelope = this.axMapControl1.Extent;
pEnvelope.CenterAt(pPoint);
this.axMapControl1.Extent = pEnvelope;
this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
// 按下鼠標右鍵繪制矩形框
else if (e.button == 2)
{
IEnvelope pEnvelop = this.axMapControl2.TrackRectangle();
this.axMapControl1.Extent = pEnvelop;
this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
}
}
為鷹眼控件 MapControl2 添加 OnMouseMove 事件,主要實現按下鼠標左鍵的時候移動矩形框,同時也改變主的圖控件的顯示范圍。代碼如下:
private void axMapControl2_OnMouseMove(object sender, IMapControlEvents2_OnMouseMoveEvent e)
{
// 如果不是左鍵按下就直接返回
if (e.button != 1) return;
IPoint pPoint = new PointClass();
pPoint.PutCoords(e.mapX, e.mapY);
this.axMapControl1.CenterAt(pPoint);
this.axMapControl1.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
}
1、 編譯運行
按 F5 編譯運行程序。
期待的鷹眼功能你已經實現了,按下左鍵在鷹眼窗口中移動,或者按下右鍵在鷹眼窗口中畫一個矩形,主地圖窗口的顯示范圍都會跟著變化。主地圖窗口中的地圖經放大縮小等操作后,鷹眼窗口的矩形框大小也會隨著改變。
在AE開發中,右鍵菜單有兩種實現方式,一是使用VS2005自帶的ContextMenuStrip控件,二是用AE封裝的IToolbarMenu接口。相比較而言,后者更為簡單實用,本文采用后者的實現方法。
?????? 1、創建右鍵菜單
?? 在Form1類里面添加如下變量的定義:
??????? //TOCControl控件變量
private ITOCControl2 m_tocControl = null;
//TOCControl中Map菜單
private IToolbarMenu m_menuMap = null;
//TOCControl中圖層菜單
private IToolbarMenu m_menuLayer = null;
????????????? 在Form1_Load函數進行初始化,即菜單的創建:
m_menuMap = new ToolbarMenuClass();
m_menuLayer = new ToolbarMenuClass();
2、添加菜單項
第1步中創建的菜單可認為是菜單容器,里面什么都沒有,具體的命令或工具作為菜單項添加到菜單容器才能工作。一般情況下,啟動程序就要完成菜單項的添加,故此工作在Form1_Load函數完成。
當然,添加菜單項之前,必須實現相應命令或工具。這里的命令或工具可以AE內置的也可以是自定義的。AE內置了許多可以直接調用的常用命令和工具,如ControlsAddDataCommandClass,在ESRI.ArcGIS.Controls命名空間中,大家可以對象瀏覽器中查看。當然,這里也可以直接調用AE內置的菜單,如ControlsFeatureSelectionMenu。另外,本講也實現三自定義命令,以做示范。它們分別為圖層可視控制命令(用于控制圖層顯示與否)、移除圖層和放大到整個圖層命令。實現方法也很簡單,就是右擊3sdnMap項目,選擇“添加|類”,選擇C#普通的類模板,用以下代碼覆蓋系統自己生成的所有代碼。
圖層可視控制類LayerVisibility代碼:
?using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.SystemUI;
namespace _sdnMap
{
??? /// <summary>
??? /// 圖層可視控制
??? /// </summary>
?????? public sealed class LayerVisibility : BaseCommand, ICommandSubType
?????? {
????????????? private IHookHelper m_hookHelper = new HookHelperClass();
????????????? private long m_subType;
????????????? public LayerVisibility()
????????????? {
????????????? }
??????
????????????? public override void OnClick()
????????????? {
???????????????????? for (int i=0; i <= m_hookHelper.FocusMap.LayerCount - 1; i++)
???????????????????? {
??????????????????????????? if (m_subType == 1) m_hookHelper.FocusMap.get_Layer(i).Visible = true;
??????????????????????????? if (m_subType == 2) m_hookHelper.FocusMap.get_Layer(i).Visible = false;
???????????????????? }
???????????????????? m_hookHelper.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography,null,null);
????????????? }
??????
????????????? public override void OnCreate(object hook)
????????????? {
???????????????????? m_hookHelper.Hook = hook;
????????????? }
??????
????????????? public int GetCount()
? ????????????{
???????????????????? return 2;
????????????? }
??????
????????????? public void SetSubType(int SubType)
????????????? {
???????????????????? m_subType = SubType;
????????????? }
??????
????????????? public override string Caption
????????????? {
???????????????????? get
???????????????????? {
??????????????????????????? if (m_subType == 1) return "Turn All Layers On";
??????????????????????????? else? return "Turn All Layers Off";
???????????????????? }
????????????? }
???? ??
????????????? public override bool Enabled
????????????? {
???????????????????? get
???????????????????? {
??????????????????????????? bool enabled = false; int i;
??????????????????????????? if (m_subType == 1)
??????????????????????????? {
? ?????????????????????????????????for (i=0;i<=m_hookHelper.FocusMap.LayerCount - 1;i++)
?????????????????????????????????? {
????????????????????????????????????????? if (m_hookHelper.ActiveView.FocusMap.get_Layer(i).Visible == false)
?????????????????? ???????????????????????{
???????????????????????????????????????????????? enabled = true;
???????????????????????????????????????????????? break;
????????????????????????????????????????? }
?????????????????????????????????? }
??????????????????????? ????}
??????????????????????????? else
??????????????????????????? {
?????????????????????????????????? for (i=0;i<=m_hookHelper.FocusMap.LayerCount - 1;i++)
?????????????????????????????????? {
????????????????????????????????????????? if (m_hookHelper.ActiveView.FocusMap.get_Layer(i).Visible == true)
????????????????????????????????????????? {
???????????????????????????????????????????????? enabled = true;
???????????????????????????????????????????????? break;
???????????????????????????????? ?????????}
?????????????????????????????????? }
??????????????????????????? }
??????????????????????????? return enabled;
???????????????????? }
????????????? }
?????? }
}
移除圖層類RemoveLayer代碼:
?????? using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
namespace _sdnMap
{
??? /// <summary>
??? /// 刪除圖層
??? /// </summary>
??? public sealed class RemoveLayer : BaseCommand
??? {
? ??????private IMapControl3 m_mapControl;
??????? public RemoveLayer()
??????? {
??????????? base.m_caption = "Remove Layer";
??????? }
??????? public override void OnClick()
??????? {
??????????? ILayer layer = (ILayer)m_mapControl.CustomProperty;
??????????? m_mapControl.Map.DeleteLayer(layer);
??????? }
??????? public override void OnCreate(object hook)
??????? {
??????????? m_mapControl = (IMapControl3)hook;
??????? }
??? }
}
放大至整個圖層類ZoomToLayer:
?????? using ESRI.ArcGIS.ADF.BaseClasses;
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
namespace _sdnMap
{
??? /// <summary>
??? /// 放大至整個圖層
??? /// </summary>
??? public sealed class ZoomToLayer : BaseCommand
??? {
??????? private IMapControl3 m_mapControl;
???? ???public ZoomToLayer()
??????? {
??????????? base.m_caption = "Zoom To Layer";
??????? }
??????? public override void OnClick()
??????? {
??????????? ILayer layer = (ILayer)m_mapControl.CustomProperty;
??????????? m_mapControl.Extent = layer.AreaOfInterest;
??????? }
??????? public override void OnCreate(object hook)
??????? {
??????????? m_mapControl = (IMapControl3)hook;
??????? }
??? }
}
以上三個工具或命令的實現代碼比較簡單,在此不過多的分析,請讀者自行理解。
下面在Form1_Load函數中進行菜單項的添加,代碼如下:
?????? //添加自定義菜單項到TOCCOntrol的Map菜單中
//打開文檔菜單
?m_menuMap.AddItem(new OpenNewMapDocument(m_controlsSynchronizer), -1, 0, false, esriCommandStyles.esriCommandStyleIconAndText);
//添加數據菜單
?m_menuMap.AddItem(new ControlsAddDataCommandClass(), -1, 1, false, esriCommandStyles.esriCommandStyleIconAndText);
?//打開全部圖層菜單
?m_menuMap.AddItem(new LayerVisibility(), 1, 2, false, esriCommandStyles.esriCommandStyleTextOnly);
//關閉全部圖層菜單
?m_menuMap.AddItem(new LayerVisibility(), 2, 3, false, esriCommandStyles.esriCommandStyleTextOnly);
?//以二級菜單的形式添加內置的“選擇”菜單
?m_menuMap.AddSubMenu("esriControls.ControlsFeatureSelectionMenu", 4, true);
//以二級菜單的形式添加內置的“地圖瀏覽”菜單
?m_menuMap.AddSubMenu("esriControls.ControlsMapViewMenu",5, true);
//添加自定義菜單項到TOCCOntrol的圖層菜單中
?m_menuLayer = new ToolbarMenuClass();
//添加“移除圖層”菜單項
?m_menuLayer.AddItem(new RemoveLayer(), -1, 0, false, esriCommandStyles.esriCommandStyleTextOnly);
//添加“放大到整個圖層”菜單項
?m_menuLayer.AddItem(new ZoomToLayer(), -1, 1, true, esriCommandStyles.esriCommandStyleTextOnly);
?//設置菜單的Hook
?m_menuLayer.SetHook(m_mapControl);
?m_menuMap.SetHook(m_mapControl);
3、
彈出右鍵菜單
顧名思義,右鍵菜單是在鼠標右鍵按下的時候彈出,所以我們要添加TOCControl1控件的OnMouseDown事件,實現代碼如下:
?????? private void axTOCControl1_OnMouseDown(object sender, ITOCControlEvents_OnMouseDownEvent e)
{
? ?????//如果不是右鍵按下直接返回
?????? if (e.button != 2) return;
?????? esriTOCControlItem item = esriTOCControlItem.esriTOCControlItemNone;
?????? IBasicMap map = null;
?????? ILayer layer = null;
?????? object other = null;
?????? object index = null;
?????? //判斷所選菜單的類型
?????? m_tocControl.HitTest(e.x, e.y, ref item, ref map, ref layer, ref other, ref index);
?????? //確定選定的菜單類型,Map或是圖層菜單
?????? if (item == esriTOCControlItem.esriTOCControlItemMap)
????????????? m_tocControl.SelectItem(map, null);
?????? else
????????????? m_tocControl.SelectItem(layer, null);
?????? //設置CustomProperty為layer (用于自定義的Layer命令)??????????????????
?????? m_mapControl.CustomProperty = layer;
?????? //彈出右鍵菜單
?????? if (item == esriTOCControlItem.esriTOCControlItemMap)
????????????? m_menuMap.PopupMenu(e.x, e.y, m_tocControl.hWnd);
?????? if (item == esriTOCControlItem.esriTOCControlItemLayer)
????????????? m_menuLayer.PopupMenu(e.x, e.y, m_tocControl.hWnd);
}
同樣的方法,我們也可以實現主地圖控件的右鍵菜單,以方便地圖瀏覽。添加MapControl1控件的OnMouseDown事件,實現代碼如下:
?????? /// <summary>
/// 主地圖控件的右鍵響應函數
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axMapControl1_OnMouseDown(object sender, IMapControlEvents2_OnMouseDownEvent e)
{
??? if (e.button == 2)
??? {
??????? //彈出右鍵菜單
??????? m_menuMap.PopupMenu(e.x,e.y,m_mapControl.hWnd);
??? }
}
4、編譯運行
按F5編譯運行程序,你會發現,原來右鍵菜單實現起來是這么的簡單啊!
到第六講為止已經發現的教程Bug及解決方法如下:
1、在第二講可能會出現變量未定義。
原因:第二講與第三講聯系緊密,我為控制篇幅才將其分為兩講,某些變量是在第三講才進行定義,請大家注意。
2、第六講彈不出TOCControl的右鍵菜單
原因:沒有取得m_tocControl的指針,即沒有把m_tocControl指針與axTOCControl1控件綁定,導致調用m_menuMap.PopupMenu(e.x, e.y, m_tocControl.hWnd);時m_tocControl.hWnd為NULL,故無法彈出菜單。
解決方法:在Form1_Load()函數中,添加如下代碼:
m_tocControl = (ITOCControl2)this.axTOCControl1.Object;
目前已經發現的優化方案如下:
1、教程第四講,坐標單位前面的esri,原用switch語句逐一替換,其實直接用取子串(Substring)的方法截去更方便。
修改代碼如下:
?CoordinateLabel.Text = " 當前坐標 X = " + e.mapX.ToString() + " Y = " + e.mapY.ToString() + " " + this.axMapControl1.MapUnits.ToString().Substring(4);
2、教程第四講,固定狀態欄中的比例尺和當前坐標項目的寬度以防止閃爍。
方法如下:
選中狀態欄中的比例尺或當前坐標項目,把其autoSize屬性設為False,再在Size屬性里設置寬度。經測試,比例尺寬度為150,當前坐標寬度為400比較合適。
這一講,我們要實現的是圖層符號選擇器,與ArcMap中的Symbol Selector的類似。本講較前幾講而言,些許有些復雜,不過只要仔細琢磨,認真操作,你就很容易實現如下所示的符號選擇器。因為本講篇幅較長,故我將其分成兩個階段,本文是第一階段。
圖1
在AE開發中,符號選擇器有兩種實現方式。
一是在程序中直接調用ArcMap中的符號選擇器,如下所示:
圖2
二是自定義符號選擇器,如圖1所示。
由于第一種方式前提是必須安裝ArcGIS Desktop,其界面還是英文的,而對二次開發來說,大部分用戶希望應該是中文界面。因此開發人員通常選擇第二種方式,本講也著重講解第二種方式。
通過對《ArcGIS Engine+C#實例開發教程》前六講的學習,我已經假定你已經基本熟悉C#語言和VS2005的操作,故在下面的教程中,我不準備說明每一步驟的具體操作方法,而只是說明操作步驟,以節省時間和篇幅。
1.??????? 直接調用ArcMap中的符號選擇器
(1)添加ESRI.ArcGIS.DisplayUI的引用。
分別在解決方案管理器和代碼中添加引用。
(2)添加TOCControl的Double_Click事件。
(3)實現TOCControl的Double_Click事件。
因為種方法不是本講的重點,故不對代碼進行分析,有興趣的讀者請自行理解或結合后面的內容理解。代碼如下:
?private void axTOCControl1_OnDoubleClick(object sender, ITOCControlEvents_OnDoubleClickEvent e)
{
??? esriTOCControlItem toccItem = esriTOCControlItem.esriTOCControlItemNone;
??? ILayer iLayer = null;
??? IBasicMap iBasicMap = null;
??? object unk = null;
??? object data = null;
??? if (e.button == 1)
??? {
??????? axTOCControl1.HitTest(e.x, e.y, ref toccItem, ref iBasicMap, ref iLayer, ref unk,
??????????? ref data);
??????? System.Drawing.Point pos = new System.Drawing.Point(e.x, e.y);
??????? if (toccItem == esriTOCControlItem.esriTOCControlItemLegendClass)
??????? {
??????????? ESRI.ArcGIS.Carto.ILegendClass pLC = new LegendClassClass();
??????????? ESRI.ArcGIS.Carto.ILegendGroup pLG = new LegendGroupClass();
??????????? if (unk is ILegendGroup)
??????????? {
??????????????? pLG = (ILegendGroup)unk;
??????????? }
??????????? pLC = pLG.get_Class((int)data);
??????????? ISymbol pSym;
??????????? pSym = pLC.Symbol;
??????????? ESRI.ArcGIS.DisplayUI.ISymbolSelector pSS = new
??????????????? ESRI.ArcGIS.DisplayUI.SymbolSelectorClass();
? ??????????bool bOK = false;
??????????? pSS.AddSymbol(pSym);
??????????? bOK = pSS.SelectSymbol(0);
??????????? if (bOK)
??????????? {
??????????????? pLC.Symbol = pSS.GetSymbolAt(0);
??????????? }
??????????? this.axMapControl1.ActiveView.Refresh();
??????????? this.axTOCControl1.Refresh();
??????? }
??? }
}
(4)編譯運行即可。
?2.??????? 自定義符號選擇器
AE9.2提供了SymbologyControl控件,極大的方便了圖層符號選擇器的制作。本講實現的符號選擇器有如下功能。
用戶雙擊TOCControl控件中圖層的符號時,彈出選擇符號對話框,對話框能夠根據圖層類型自動加載相應的符號,如點、線、面。用戶可以調整符號的顏色、線寬、角度等參數。還可以打開自定義的符號文件(*.ServerStyle),加載更多的符號。
2.1???? 新建符號選擇器窗體
新建Winodws窗體,命名為SymbolSelectorFrm,修改窗體的Text屬性為“選擇符號”。并添加SymboloryControl、PictureBox、Button、Label、NumericUpDown、GroupBox、ColorDialog、OpenFileDialog、ContextMenuStrip控件??丶季秩缦滤?#xff1a;
圖3
2.2???? 設置控件屬性
設置相應控件的相關屬性,如下表所示(空則不用修改):
控件
?Name屬性
?Text屬性
?其它
SymbologyControl
?axSymbologyControl
PictureBox
?ptbPreview
Label
?lblColor
?顏色
Label
?lblSize
?大小
Label
?lblWidth
?線寬
Label
?lblAngle
?角度
Label
?lblOutlineColor
?外框顏色
NumericUpDown
?nudSize
NumericUpDown
?nudWidth
NumericUpDown
?nudAngle
Button
?btnColor
?(設置為空)
Button
?btnOutlineColor
?(設置為空)
Button
?btnMoreSymbols
?更多符號
Button
?btnOK
?確定
?DialogResult屬性設為OK
Button
?btnCancel
?取消
GroupBox
?groupBox1
?預覽
GroupBox
?groupBox2
?設置
ColorDialog
?colorDialog
OpenFileDialog
?openFileDialog
?Filter屬性設置為:
Styles 文件|*.ServerStyle
ContextMenuStrip
?contextMenuStripMoreSymbol
2.3???? 添加引用
在解決方案資源管理器中添加ArcGIS Engine的ESRI.ArcGIS.Geodatabase引用,在SymbolSelectorFrm.cs文件中添加如下引用代碼:
?? using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.Geodatabase;
2.4?? 初始化
(1)?????? 添加SymbolSelectorFrm的全局變量,代碼如下:
private IStyleGalleryItem pStyleGalleryItem;
private ILegendClass pLegendClass;
private ILayer pLayer;
public ISymbol pSymbol;
public Image pSymbolImage;
(2)?????? 修改SymbolSelectorFrm的構造函數,傳入圖層和圖例接口。代碼如下:
?? /// <summary>
/// 構造函數,初始化全局變量
/// </summary>
/// <param name="tempLegendClass">TOC圖例</param>
/// <param name="tempLayer">圖層</param>
public SymbolSelectorFrm(ILegendClass tempLegendClass, ILayer tempLayer)
{
??? InitializeComponent();
??? this.pLegendClass = tempLegendClass;
??? this.pLayer = tempLayer;
}
(3)?????? 添加SymbolControl的SymbologyStyleClass設置函數SetFeatureClassStyle(),代碼如下:
/// <summary>
/// 初始化SymbologyControl的StyleClass,圖層如果已有符號,則把符號添加到SymbologyControl中的第一個符號,并選中
/// </summary>
/// <param name="symbologyStyleClass"></param>
private void SetFeatureClassStyle(esriSymbologyStyleClass symbologyStyleClass)
{
??? this.axSymbologyControl.StyleClass = symbologyStyleClass;
??? ISymbologyStyleClass pSymbologyStyleClass = this.axSymbologyControl.GetStyleClass(symbologyStyleClass);
??? if (this.pLegendClass != null)
??? {
??????? IStyleGalleryItem currentStyleGalleryItem = new ServerStyleGalleryItem();
??????? currentStyleGalleryItem.Name = "當前符號";
??????? currentStyleGalleryItem.Item = pLegendClass.Symbol;
??????? pSymbologyStyleClass.AddItem(currentStyleGalleryItem,0);
??????? this.pStyleGalleryItem = currentStyleGalleryItem;
??? }
??? pSymbologyStyleClass.SelectItem(0);
}
(4)?????? 添加注冊表讀取函數ReadRegistry(),此函數從注冊表中讀取ArcGIS的安裝路徑,代碼如下:
??? /// <summary>
/// 從注冊表中取得指定軟件的路徑
/// </summary>
/// <param name="sKey"></param>
/// <returns></returns>
private string ReadRegistry(string sKey)
{
??? //Open the subkey for reading
??? Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(sKey, true);
??? if (rk == null) return "";
??? // Get the data from a specified item in the key.
??? return (string)rk.GetValue("InstallDir");
}
(5)? ?????添加SymbolSelectorFrm的Load事件。根據圖層類型為SymbologyControl導入相應的符號樣式文件,如點、線、面,并設置控件的可視性。代碼如下:
private void SymbolSelectorFrm_Load(object sender, EventArgs e)
{
//取得ArcGIS安裝路徑
string sInstall = ReadRegistry("SOFTWARE\\ESRI\\CoreRuntime");
//載入ESRI.ServerStyle文件到SymbologyControl
this.axSymbologyControl.LoadStyleFile(sInstall + "\\Styles\\ESRI.ServerStyle");
//確定圖層的類型(點線面),設置好SymbologyControl的StyleClass,設置好各控件的可見性(visible)
IGeoFeatureLayer pGeoFeatureLayer = (IGeoFeatureLayer)pLayer;
switch (((IFeatureLayer)pLayer).FeatureClass.ShapeType)
{
??? case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPoint:
this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassMarkerSymbols);
??????? this.lblAngle.Visible = true;
??????? this.nudAngle.Visible = true;
??????? this.lblSize.Visible = true;
??????? this.nudSize.Visible = true;
??????? this.lblWidth.Visible = false;
??????? this.nudWidth.Visible = false;
??????? this.lblOutlineColor.Visible = false;
??????? this.btnOutlineColor.Visible = false;
??????? break;
??? case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolyline:
??????? this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassLineSymbols);
??????? this.lblAngle.Visible = false;
??????? this.nudAngle.Visible = false;
??????? this.lblSize.Visible = false;
??????? this.nudSize.Visible = false;
??????? this.lblWidth.Visible = true;
??????? this.nudWidth.Visible = true;
??????? this.lblOutlineColor.Visible = false;
??????? this.btnOutlineColor.Visible = false;
? ??????break;
??? case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryPolygon:
??????? this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassFillSymbols);
??????? this.lblAngle.Visible = false;
??????? this.nudAngle.Visible = false;
????? ??this.lblSize.Visible = false;
??????? this.nudSize.Visible = false;
??????? this.lblWidth.Visible = true;
??????? this.nudWidth.Visible = true;
??????? this.lblOutlineColor.Visible = true;
??????? this.btnOutlineColor.Visible = true;
??????? break;
??? case ESRI.ArcGIS.Geometry.esriGeometryType.esriGeometryMultiPatch:
??????? this.SetFeatureClassStyle(esriSymbologyStyleClass.esriStyleClassFillSymbols);
??????? this.lblAngle.Visible = false;
??????? this.nudAngle.Visible = false;
??????? this.lblSize.Visible = false;
??????? this.nudSize.Visible = false;
??????? this.lblWidth.Visible = true;
??????? this.nudWidth.Visible = true;
??????? this.lblOutlineColor.Visible = true;
??????? this.btnOutlineColor.Visible = true;
??????? break;
??? default:
??????? this.Close();
???? break;
}
}
(6)?????? 雙擊確定按鈕和取消按鈕,分別添加如下代碼:
??? /// <summary>
/// 確定按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnOK_Click(object sender, EventArgs e)
{
??? //取得選定的符號
??? this.pSymbol = (ISymbol)pStyleGalleryItem.Item;
??? //更新預覽圖像
??? this.pSymbolImage = this.ptbPreview.Image;
??? //關閉窗體
??? this.Close();
}
/// <summary>
/// 取消按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnCancel_Click(object sender, EventArgs e)
{
??? this.Close();
}
(7)?????? 為了操作上的方便,我們添加SymbologyControl的DoubleClick事件,當雙擊符號時同按下確定按鈕一樣,選定符號并關閉符號選擇器窗體。代碼如下:
??? /// <summary>
/// 雙擊符號同單擊確定按鈕,關閉符號選擇器。
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axSymbologyControl_OnDoubleClick(object sender, ESRI.ArcGIS.Controls.ISymbologyControlEvents_OnDoubleClickEvent e)
{
??? this.btnOK.PerformClick();
}
(8)?????? 再添加符號預覽函數,當用戶選定某一符號時,符號可以顯示在PictureBox控件中,方便預覽,函數代碼如下:
/// <summary>
/// 把選中并設置好的符號在picturebox控件中預覽
/// </summary>
private void PreviewImage()
{
??? stdole.IPictureDisp picture = this.axSymbologyControl.GetStyleClass(this.axSymbologyControl.StyleClass).PreviewItem(pStyleGalleryItem, this.ptbPreview.Width, this.ptbPreview.Height);
??? System.Drawing.Image image = System.Drawing.Image.FromHbitmap(new System.IntPtr(picture.Handle));
??? this.ptbPreview.Image = image;
}
(9)?????? 當SymbologyControl的樣式改變時,需要重新設置符號參數調整控件的可視性,故要添加SymbologyControl的OnStyleClassChanged事件,事件代碼與Load事件類似,如下:
??? /// <summary>
/// 當樣式(Style)改變時,重新設置符號類型和控件的可視性
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axSymbologyControl_OnStyleClassChanged(object sender, ESRI.ArcGIS.Controls.ISymbologyControlEvents_OnStyleClassChangedEvent e)
{
??? switch ((esriSymbologyStyleClass)(e.symbologyStyleClass))
??? {
??????? case esriSymbologyStyleClass.esriStyleClassMarkerSymbols:
??????????? this.lblAngle.Visible = true;
??????????? this.nudAngle.Visible = true;
??????????? this.lblSize.Visible = true;
??????????? this.nudSize.Visible = true;
??????????? this.lblWidth.Visible = false;
??????????? this.nudWidth.Visible = false;
??????????? this.lblOutlineColor.Visible = false;
??????????? this.btnOutlineColor.Visible = false;
??????????? break;
??????? case esriSymbologyStyleClass.esriStyleClassLineSymbols:
??????????? this.lblAngle.Visible = false;
??????????? this.nudAngle.Visible = false;
??????????? this.lblSize.Visible = false;
??????????? this.nudSize.Visible = false;
??????????? this.lblWidth.Visible = true;
??????????? this.nudWidth.Visible = true;
??????????? this.lblOutlineColor.Visible = false;
??????????? this.btnOutlineColor.Visible = false;
??????????? break;
??????? case esriSymbologyStyleClass.esriStyleClassFillSymbols:
??????????? this.lblAngle.Visible = false;
??????????? this.nudAngle.Visible = false;
??????????? this.lblSize.Visible = false;
??????????? this.nudSize.Visible = false;
??????????? this.lblWidth.Visible = true;
??????????? this.nudWidth.Visible = true;
??????????? this.lblOutlineColor.Visible = true;
??????????? this.btnOutlineColor.Visible = true;
??????????? break;
??? }
}
2.5???? 調用自定義符號選擇器
通過以上操作,本符號選擇器雛形已經完成,我們可以3sdnMap主窗體中調用并進行測試。如果您已經完成“直接調用ArcMap中的符號選擇器”這一節,請注釋axTOCControl1_OnDoubleClick事件響應函數里的代碼,并添加如下代碼。如果您是直接學習自定義符號選擇器這一節的,請先添加axTOCControl1控件的OnDoubleClick事件,再添加如下事件響應函數代碼:
?? /// <summary>
/// 雙擊TOCControl控件時觸發的事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axTOCControl1_OnDoubleClick(object sender, ITOCControlEvents_OnDoubleClickEvent e)
{
??? esriTOCControlItem itemType = esriTOCControlItem.esriTOCControlItemNone;
??? IBasicMap basicMap = null;
??? ILayer layer = null;
??? object unk = null;
??? object data = null;
??? axTOCControl1.HitTest(e.x, e.y, ref itemType, ref basicMap, ref layer, ref unk, ref data);
??? if (e.button == 1)
??? {
??????? if(itemType==esriTOCControlItem.esriTOCControlItemLegendClass)
??????? {????????????
??????????????? //取得圖例
??????????????? ILegendClass pLegendClass = ((ILegendGroup)unk).get_Class((int)data);
??????????????? //創建符號選擇器SymbolSelector實例
??????????????? SymbolSelectorFrm SymbolSelectorFrm = new SymbolSelectorFrm(pLegendClass, layer);
??????????????? if (SymbolSelectorFrm.ShowDialog() == DialogResult.OK)
??????????????? {
??????????????????? //局部更新主Map控件
??????????????????? m_mapControl.ActiveView.PartialRefresh(esriViewDrawPhase.esriViewGeography, null, null);
??????????????????? //設置新的符號
??????????????????? pLegendClass.Symbol = SymbolSelectorFrm.pSymbol;
??????????????????? //更新主Map控件和圖層控件
??????????????????? this.axMapControl1.ActiveView.Refresh();
?????????? ?????????this.axTOCControl1.Refresh();
??????????????? }
??????? }
}
?????? 按F5編譯運行,相信你已經看到自己新手打造的符號選擇器已經出現在眼前了。當然,它還比較簡陋,下面我們將一起把它做得更完美些。
2.6???? 符號參數調整
在地圖整飾中,符號參數的調整是必須的功能。下面我們將實現符號顏色、外框顏色、線寬、角度等參數的調整。
(1)?????? 添加SymbologyControl的OnItemSelected事件,此事件在鼠標選中符號時觸發,此時顯示出選定符號的初始參數,事件響應函數代碼如下:
/// <summary>
/// 選中符號時觸發的事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void axSymbologyControl_OnItemSelected(object sender, ESRI.ArcGIS.Controls.ISymbologyControlEvents_OnItemSelectedEvent e)
{
??? pStyleGalleryItem = (IStyleGalleryItem)e.styleGalleryItem;
??? Color color;
??? switch (this.axSymbologyControl.StyleClass)
??? {
??????????? //點符號
??????? case esriSymbologyStyleClass.esriStyleClassMarkerSymbols:
??????????? color = this.ConvertIRgbColorToColor(((IMarkerSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
??????????? //設置點符號角度和大小初始值
??????????? this.nudAngle.Value = (decimal)((IMarkerSymbol)this.pStyleGalleryItem.Item).Angle;
???????? ???this.nudSize.Value = (decimal)((IMarkerSymbol)this.pStyleGalleryItem.Item).Size;
??????????? break;
??????????? //線符號
??????? case esriSymbologyStyleClass.esriStyleClassLineSymbols:
??????????? color = this.ConvertIRgbColorToColor(((ILineSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
??????????? //設置線寬初始值
??????????? this.nudWidth.Value = (decimal)((ILineSymbol)this.pStyleGalleryItem.Item).Width;
??????????? break;
??????????? //面符號
??????? case esriSymbologyStyleClass.esriStyleClassFillSymbols:
??????????? color = this.ConvertIRgbColorToColor(((IFillSymbol)pStyleGalleryItem.Item).Color as IRgbColor);
??????????? this.btnOutlineColor.BackColor = this.ConvertIRgbColorToColor(((IFillSymbol)pStyleGalleryItem.Item).Outline.Color as IRgbColor);
??????????? //設置外框線寬度初始值
??????????? this.nudWidth.Value = (decimal)((IFillSymbol)this.pStyleGalleryItem.Item).Outline.Width;
??????????? break;
??????? default:
??????????? color = Color.Black;
??????????? break;
??? }
??? //設置按鈕背景色
??? this.btnColor.BackColor = color;
??? //預覽符號
??? this.PreviewImage();
}
?
(2)?????? 調整點符號的大小
添加nudSize控件的ValueChanged事件,即在控件的值改變時響應此事件,然后重新設置點符號的大小。代碼如下:
??? /// <summary>
/// 調整符號大小-點符號
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void nudSize_ValueChanged(object sender, EventArgs e)
{
??? ((IMarkerSymbol)this.pStyleGalleryItem.Item).Size = (double)this.nudSize.Value;
??? this.PreviewImage();
}
(3)?????? 調整點符號的角度
添加nudAngle控件的ValueChanged事件,以重新設置點符號的角度。代碼如下:
??? /// <summary>
/// 調整符號角度-點符號
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void nudAngle_ValueChanged(object sender, EventArgs e)
{
??? ((IMarkerSymbol)this.pStyleGalleryItem.Item).Angle = (double)this.nudAngle.Value;
??? this.PreviewImage();
}
(4)?????? 調整線符號和面符號的線寬
添加nudWidth控件的ValueChanged事件,以重新設置線符號的線寬和面符號的外框線的線寬。代碼如下:
?
/// <summary>
/// 調整符號寬度-限于線符號和面符號
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void nudWidth_ValueChanged(object sender, EventArgs e)
{
??? switch (this.axSymbologyControl.StyleClass)
??? {
??????? case esriSymbologyStyleClass.esriStyleClassLineSymbols:
??????????? ((ILineSymbol)this.pStyleGalleryItem.Item).Width = Convert.ToDouble(this.nudWidth.Value);
??????????? break;
??????? case esriSymbologyStyleClass.esriStyleClassFillSymbols:
??????????? //取得面符號的輪廓線符號
??????????? ILineSymbol pLineSymbol = ((IFillSymbol)this.pStyleGalleryItem.Item).Outline;
??????????? pLineSymbol.Width = Convert.ToDouble(this.nudWidth.Value);
??????????? ((IFillSymbol)this.pStyleGalleryItem.Item).Outline = pLineSymbol;
??????????? break;
??? }
??? this.PreviewImage();
}
(5)?????? 顏色轉換
在ArcGIS Engine中,顏色由IRgbColor接口實現,而在.NET框架中,顏色則由Color結構表示。故在調整顏色參數之前,我們必須完成以上兩種不同顏色表示方式的轉換。關于這兩種顏色結構的具體信息,請大家自行查閱相關資料。下面添加兩個顏色轉換函數。
ArcGIS Engine中的IRgbColor接口轉換至.NET中的Color結構的函數:
??? /// <summary>
/// 將ArcGIS Engine中的IRgbColor接口轉換至.NET中的Color結構
/// </summary>
/// <param name="pRgbColor">IRgbColor</param>
/// <returns>.NET中的System.Drawing.Color結構表示ARGB顏色</returns>
public Color ConvertIRgbColorToColor(IRgbColor pRgbColor)
{
??? return ColorTranslator.FromOle(pRgbColor.RGB);
}
.NET中的Color結構轉換至于ArcGIS Engine中的IColor接口的函數:
??? /// <summary>
/// 將.NET中的Color結構轉換至于ArcGIS Engine中的IColor接口
/// </summary>
/// <param name="color">.NET中的System.Drawing.Color結構表示ARGB顏色</param>
/// <returns>IColor</returns>
public IColor ConvertColorToIColor(Color color)
{
??? IColor pColor = new RgbColorClass();
??? pColor.RGB = color.B * 65536 + color.G * 256 + color.R;
??? return pColor;
}
(6)?????? 調整所有符號的顏色
選擇顏色時,我們調用.NET的顏色對話框ColorDialog,選定顏色后,修改顏色按鈕的背景色為選定的顏色,以方便預覽。雙擊btnColor按鈕,添加如下代碼:
/// <summary>
/// 顏色按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnColor_Click(object sender, EventArgs e)
{
??? //調用系統顏色對話框
??? if (this.colorDialog.ShowDialog() == DialogResult.OK)
??? {
??????? //將顏色按鈕的背景顏色設置為用戶選定的顏色
??????? this.btnColor.BackColor = this.colorDialog.Color;
??????? //設置符號顏色為用戶選定的顏色
??????? switch (this.axSymbologyControl.StyleClass)
??????? {
??????????? //點符號
??????????? case esriSymbologyStyleClass.esriStyleClassMarkerSymbols:
??????????????? ((IMarkerSymbol)this.pStyleGalleryItem.Item).Color = this.ConvertColorToIColor(this.colorDialog.Color);
??????????????? break;
??????????? //線符號
??????????? case esriSymbologyStyleClass.esriStyleClassLineSymbols:
??????????????? ((ILineSymbol)this.pStyleGalleryItem.Item).Color = this.ConvertColorToIColor(this.colorDialog.Color);
??????????????? break;
??????????? //面符號
??????????? case esriSymbologyStyleClass.esriStyleClassFillSymbols:
??????????????? ((IFillSymbol)this.pStyleGalleryItem.Item).Color = this.ConvertColorToIColor(this.colorDialog.Color);
??????????????? break;
??????? }
??????? //更新符號預覽
??????? this.PreviewImage();
??? }
}
(7)?????? 調整面符號的外框線顏色
同上一步類似,雙擊btnOutlineColor按鈕,添加如下代碼:
?
/// <summary>
/// 外框顏色按鈕
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnOutlineColor_Click(object sender, EventArgs e)
{
??? if (this.colorDialog.ShowDialog() == DialogResult.OK)
??? {
??????? //取得面符號中的外框線符號
??????? ILineSymbol pLineSymbol = ((IFillSymbol)this.pStyleGalleryItem.Item).Outline;
??????? //設置外框線顏色
??????? pLineSymbol.Color = this.ConvertColorToIColor(this.colorDialog.Color);
??????? //重新設置面符號中的外框線符號
??????? ((IFillSymbol)this.pStyleGalleryItem.Item).Outline = pLineSymbol;
??????? //設置按鈕背景顏色
??????? this.btnOutlineColor.BackColor = this.colorDialog.Color;
??????? //更新符號預覽
??????? this.PreviewImage();
??? }
}
?????? 至此,你可以編譯運行程序,看看效果如何,是不是感覺很不錯了?我們已經能夠修改符號的參數,自定義符號了。
?????? 但是,SymbologyControl默認加載的是ESRI.ServerStyle文件的樣式,用過ArcMap的你可能已經注意到,ArcMap中的Symbol Selector有一個“More Symbols”按鈕,可以加載其它的符號和ServerStyle文件。3sdnMap當然“一個都不能少”。
2.7???? 添加更多符號菜單
還記得我們在開始的時候添加了ContextMenuStrip控件嗎?現在它終于派上用場了。我們要實現的功能是:單擊“更多符號”彈出菜單(ContextMenu),菜單中列出了ArcGIS自帶的其它符號,勾選相應的菜單項就可以在SymbologyControl中增加相應的符號。在菜單的最后一項是“添加符號”,選擇這一項時,將彈出打開文件對話框,我們可以由此選擇其它的ServerStyle文件,以加載更多的符號。
(1)?????? 定義全局變量
在SymbolSelectorFrm中定義如下全局變量,用于判斷菜單是否已經初始化。
?//菜單是否已經初始化標志
bool contextMenuMoreSymbolInitiated = false;
(2)?????? 雙擊“更多符號”按鈕,添加Click事件。
在此事件響應函數中,我們要完成ServerStyle文件的讀取,將其文件名作為菜單項名稱生成菜單并顯示菜單。代碼如下:
?
/// <summary>
/// “更多符號”按下時觸發的事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnMoreSymbols_Click(object sender, EventArgs e)
{
??? if (this.contextMenuMoreSymbolInitiated == false)
??? {
?????? ?string sInstall = ReadRegistry("SOFTWARE\\ESRI\\CoreRuntime");
??????? string path = System.IO.Path.Combine(sInstall, "Styles");
??????? //取得菜單項數量
??????? string[] styleNames = System.IO.Directory.GetFiles(path, "*.ServerStyle");
??????? ToolStripMenuItem[] symbolContextMenuItem = new ToolStripMenuItem[styleNames.Length + 1];
??????? //循環添加其它符號菜單項到菜單
??????? for (int i = 0; i < styleNames.Length; i++)
??????? {
??????????? symbolContextMenuItem[i] = new ToolStripMenuItem();
??????????? symbolContextMenuItem[i].CheckOnClick = true;
??????????? symbolContextMenuItem[i].Text = System.IO.Path.GetFileNameWithoutExtension(styleNames[i]);
??????????? if (symbolContextMenuItem[i].Text == "ESRI")
??????????? {
??????????????? symbolContextMenuItem[i].Checked = true;
??????????? }
??????????? symbolContextMenuItem[i].Name = styleNames[i];
??????? }
??????? //添加“更多符號”菜單項到菜單最后一項
??????? symbolContextMenuItem[styleNames.Length] = new ToolStripMenuItem();
??????? symbolContextMenuItem[styleNames.Length].Text = "添加符號";
??????? symbolContextMenuItem[styleNames.Length].Name = "AddMoreSymbol";
??????? //添加所有的菜單項到菜單
??????? this.contextMenuStripMoreSymbol.Items.AddRange(symbolContextMenuItem);
??????? this.contextMenuMoreSymbolInitiated = true;
??? }
??? //顯示菜單
??? this.contextMenuStripMoreSymbol.Show(this.btnMoreSymbols.Location);
}
(3)?????? 添加contextMenuStripMoreSymbol控件的ItemClicked事件。
當單擊某一菜單項時響應ItemClicked事件,將選中的ServerStyle文件導入到SymbologyControl中并刷新。當用戶單擊“添加符號”菜單項時,彈出打開文件對話框,供用戶選擇其它的ServerStyle文件。代碼如下:
?
/// <summary>
/// “更多符號”按鈕彈出的菜單項單擊事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void contextMenuStripMoreSymbol_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
{
??? ToolStripMenuItem pToolStripMenuItem = (ToolStripMenuItem)e.ClickedItem;
??? //如果單擊的是“添加符號”
??? if (pToolStripMenuItem.Name == "AddMoreSymbol")
??? {
??????? //彈出打開文件對話框
??????? if (this.openFileDialog.ShowDialog() == DialogResult.OK)
??????? {
?????????? ?//導入style file到SymbologyControl
??????????? this.axSymbologyControl.LoadStyleFile(this.openFileDialog.FileName);
??????????? //刷新axSymbologyControl控件
??????????? this.axSymbologyControl.Refresh();
??????? }
??? }
??? else//如果是其它選項
??? {
??????? if (pToolStripMenuItem.Checked == false)
??????? {
??????????? this.axSymbologyControl.LoadStyleFile(pToolStripMenuItem.Name);
??????????? this.axSymbologyControl.Refresh();
??????? }
??????? else
??????? {
??????????? this.axSymbologyControl.RemoveFile(pToolStripMenuItem.Name);
??????????? this.axSymbologyControl.Refresh();??????????
??????? }
??? }??????????
}???
2.8???? 編譯運行
相信你已經盼這一步很久了吧,按照慣例,按下F5吧!大功造成。
以上代碼在AE9.2+VS2005+XP中編譯通過。
在ArcMap中,單擊圖層右鍵菜單中的“Open Attribute Table”命令,便可彈出屬性數據表。本講將完成類似的功能,效果如下:
圖1
數據表顯示,我們用了DataGridView控件。DataGridView 控件提供一種強大而靈活的以表格形式顯示數據的方式。可以使用 DataGridView 控件來顯示少量數據的只讀視圖,也可以對其進行縮放以顯示特大數據集的可編輯視圖。我們可以很方便地把一個DataTable作為數據源綁定到DataGridView控件中。
本講的思路大體如下:首先根據圖層屬性中的字段創建一個空的DataTable,然后根據數據內容一行行填充DataTable數據,再將DataTable綁定到DataGridView控件,最后調用并顯示屬性表窗體。
1.創建屬性表窗體
新建一個Windows窗體,命名為“AttributeTableFrm.cs”。
從工具箱拖一個DataGridView控件到窗體,并將其Dock屬性設置為“Fill”。
添加如下引用:
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.SystemUI;
using ESRI.ArcGIS.Geometry;
using ESRI.ArcGIS.Geodatabase;
2.創建空DataTable
首先傳入ILayer,再查詢到ITable,從ITable中的Fileds中獲得每個Field,再根據Filed設置DataTable的DataColumn,由此創建一個只含圖層字段的空DataTable。實現函數如下:
/// <summary>
/// 根據圖層字段創建一個只含字段的空DataTable
/// </summary>
/// <param name="pLayer"></param>
/// <param name="tableName"></param>
/// <returns></returns>
private static DataTable CreateDataTableByLayer(ILayer pLayer, string tableName)
{
//創建一個DataTable表
DataTable pDataTable = new DataTable(tableName);
//取得ITable接口
ITable pTable = pLayer as ITable;
IField pField = null;
DataColumn pDataColumn;
//根據每個字段的屬性建立DataColumn對象
for (int i = 0; i < pTable.Fields.FieldCount; i++)
{
pField = pTable.Fields.get_Field(i);
//新建一個DataColumn并設置其屬性
pDataColumn = new DataColumn(pField.Name);
if (pField.Name == pTable.OIDFieldName)
{
pDataColumn.Unique = true;//字段值是否唯一
}
//字段值是否允許為空
pDataColumn.AllowDBNull = pField.IsNullable;
//字段別名
pDataColumn.Caption = pField.AliasName;
//字段數據類型
pDataColumn.DataType = System.Type.GetType(ParseFieldType(pField.Type));
//字段默認值
pDataColumn.DefaultValue = pField.DefaultValue;
//當字段為String類型是設置字段長度
if (pField.VarType == 8)
{
pDataColumn.MaxLength = pField.Length;
}
//字段添加到表中
pDataTable.Columns.Add(pDataColumn);
pField = null;
pDataColumn = null;
}
return pDataTable;
}
因為GeoDatabase的數據類型與.NET的數據類型不同,故要進行轉換。轉換函數如下:
/// <summary>
/// 將GeoDatabase字段類型轉換成.Net相應的數據類型
/// </summary>
/// <param name="fieldType">字段類型</param>
/// <returns></returns>
public static string ParseFieldType(esriFieldType fieldType)
{
switch (fieldType)
{
case esriFieldType.esriFieldTypeBlob:
return "System.String";
case esriFieldType.esriFieldTypeDate:
return "System.DateTime";
case esriFieldType.esriFieldTypeDouble:
return "System.Double";
case esriFieldType.esriFieldTypeGeometry:
return "System.String";
case esriFieldType.esriFieldTypeGlobalID:
return "System.String";
case esriFieldType.esriFieldTypeGUID:
return "System.String";
case esriFieldType.esriFieldTypeInteger:
return "System.Int32";
case esriFieldType.esriFieldTypeOID:
return "System.String";
case esriFieldType.esriFieldTypeRaster:
return "System.String";
case esriFieldType.esriFieldTypeSingle:
return "System.Single";
case esriFieldType.esriFieldTypeSmallInteger:
return "System.Int32";
case esriFieldType.esriFieldTypeString:
return "System.String";
default:
return "System.String";
}
}
3.裝載DataTable數據
從上一步得到的DataTable還沒有數據,只有字段信息。因此,我們要通過ICursor從ITable中逐一取出每一行數據,即IRow。再創建DataTable中相應的DataRow,根據IRow設置DataRow信息,再將所有的DataRow添加到DataTable中,就完成了DataTable數據的裝載。
為保證效率,一次最多只裝載2000條數據到DataGridView。函數代碼如下:
/// <summary>
/// 填充DataTable中的數據
/// </summary>
/// <param name="pLayer"></param>
/// <param name="tableName"></param>
/// <returns></returns>
public static DataTable CreateDataTable(ILayer pLayer, string tableName)
{
//創建空DataTable
DataTable pDataTable = CreateDataTableByLayer(pLayer, tableName);
//取得圖層類型
string shapeType = getShapeType(pLayer);
//創建DataTable的行對象
DataRow pDataRow = null;
//從ILayer查詢到ITable
ITable pTable = pLayer as ITable;
ICursor pCursor = pTable.Search(null, false);
//取得ITable中的行信息
IRow pRow = pCursor.NextRow();
int n = 0;
while (pRow != null)
{
//新建DataTable的行對象
pDataRow = pDataTable.NewRow();
for (int i = 0; i < pRow.Fields.FieldCount; i++)
{
//如果字段類型為esriFieldTypeGeometry,則根據圖層類型設置字段值
if (pRow.Fields.get_Field(i).Type == esriFieldType.esriFieldTypeGeometry)
{
pDataRow = shapeType;
}
//當圖層類型為Anotation時,要素類中會有esriFieldTypeBlob類型的數據,
//其存儲的是標注內容,如此情況需將對應的字段值設置為Element
else if (pRow.Fields.get_Field(i).Type == esriFieldType.esriFieldTypeBlob)
{
pDataRow = "Element";
}
else
{
pDataRow = pRow.get_Value(i);
}
}
//添加DataRow到DataTable
pDataTable.Rows.Add(pDataRow);
pDataRow = null;
n++;
//為保證效率,一次只裝載最多條記錄
if (n == 2000)
{
pRow = null;
}
else
{
pRow = pCursor.NextRow();
}
}
return pDataTable;
}
上面的代碼中涉及到一個獲取圖層類型的函數getShapeTape,此函數是通過ILayer判斷圖層類型的,代碼如下:
/// <summary>
/// 獲得圖層的Shape類型
/// </summary>
/// <param name="pLayer">圖層</param>
/// <returns></returns>
public static string getShapeType(ILayer pLayer)
{
IFeatureLayer pFeatLyr = (IFeatureLayer)pLayer;
switch (pFeatLyr.FeatureClass.ShapeType)
{
case esriGeometryType.esriGeometryPoint:
return "Point";
case esriGeometryType.esriGeometryPolyline:
return "Polyline";
case esriGeometryType.esriGeometryPolygon:
return "Polygon";
default:
return "";
}
}
4.綁定DataTable到DataGridView
通過以上步驟,我們已經得到了一個含有圖層屬性數據的DataTable?,F定義一個AttributeTableFrm類的成員變量:
public DataTable attributeTable;
通過以下函數,我們很容易將其綁定到DataGridView控件中。
/// <summary>
/// 綁定DataTable到DataGridView
/// </summary>
/// <param name="player"></param>
public void CreateAttributeTable(ILayer player)
{
string tableName;
tableName = getValidFeatureClassName(player .Name );
attributeTable = CreateDataTable(player,tableName );
this.dataGridView1 .DataSource = attributeTable ;
this.Text = "屬性表[" + tableName + "] " + "記錄數:"+attributeTable.Rows.Count .ToString();
}
因為DataTable的表名不允許含有“.”,因此我們用“_”替換。函數如下:
/// <summary>
/// 替換數據表名中的點
/// </summary>
/// <param name="FCname"></param>
/// <returns></returns>
public static string getValidFeatureClassName(string FCname)
{
int dot = FCname.IndexOf(".");
if (dot != -1)
{
return FCname.Replace(".", "_");
}
return FCname;
}
5.調用屬性表窗體
通過1-4步驟,我們封裝了一個AttributeTableFrm類,此類能夠由ILayer顯示圖層中的屬性表數據。那怎么調用AttributeTableFrm呢?
前面已經提到,我們是在TOCControl選中圖層的右鍵菜單中彈出屬性表窗體的,因此我們需要添加一個菜單項到TOCControl中Layer的右鍵菜單。而在第六講中,我們采用的是AE中的IToolbarMenu實現右鍵菜單的,故我們還需自定義一個Command,實現打開屬性表的功能。
以ArcGIS的Base Command為模板新建項“OpenAttributeTable.cs”。
注意:新建Base Command模板時,會彈出一個對話框讓我們選擇模板適用對象,這時我們要選擇MapControl、PageLayoutControl,即選擇第二項或者倒數第二項。
添加如下引用:
using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Display;
using ESRI.ArcGIS.esriSystem;
添加成員變量:
private ILayer m_pLayer;
修改構造函數為:
public OpenAttributeTable(ILayer pLayer)
{
//
// TODO: Define values for the public properties
//
base.m_category = ""; //localizable text
base.m_caption = "打開屬性表"; //localizable text
base.m_message = "打開屬性表"; //localizable text
base.m_toolTip = "打開屬性表"; //localizable text
base.m_name = "打開屬性表"; //unique id, non-localizable (e.g. "MyCategory_MyCommand")
m_pLayer = pLayer;
try
{
//
// TODO: change bitmap name if necessary
//
string bitmapResourceName = GetType().Name + ".bmp";
base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
}
}
再在On_Click函數中添加如下代碼,以創建并打開屬性表窗體。
/// <summary>
/// Occurs when this command is clicked
/// </summary>
public override void OnClick()
{
// TODO: Add OpenAttributeTable.OnClick implementation
AttributeTableFrm attributeTable = new AttributeTableFrm();
attributeTable.CreateAttributeTable(m_pLayer);
attributeTable.ShowDialog();
}
至此,我們完成了OpenAttributeTable命令。顯然,我們要在TOCControl的OnMouseDown事件中調用此命令。
因為,當前選中的圖層參數,即ILayer是通過OpenAttributeTable的構造函數傳入的,而選中的ILayer是動態變化的,所以我們無法在窗體初始化的Form1_Load事件中就添加OpenAttributeTable菜單項到右鍵菜單。但我們可以在OnMouseDown事件中動態添加OpenAttributeTable菜單項。
要注意的是,最后我們必須移除添加的OpenAttributeTable菜單項,不然每次按下右鍵都會添加此菜單項,將造成右鍵菜單中含有多個OpenAttributeTable菜單項。
修改TOCControl的OnMouseDown事件的部分代碼如下:
private void axTOCControl1_OnMouseDown(object sender, ITOCControlEvents_OnMouseDownEvent e)
{
//……
//彈出右鍵菜單
if (item == esriTOCControlItem.esriTOCControlItemMap)
m_menuMap.PopupMenu(e.x, e.y, m_tocControl.hWnd);
if (item == esriTOCControlItem.esriTOCControlItemLayer)
{
//動態添加OpenAttributeTable菜單項
m_menuLayer.AddItem(new OpenAttributeTable(layer), -1, 2, true, esriCommandStyles.esriCommandStyleTextOnly);
m_menuLayer.PopupMenu(e.x, e.y, m_tocControl.hWnd);
//移除OpenAttributeTable菜單項,以防止重復添加
m_menuLayer.Remove(2);
}
}
6.編譯運行
按下F5,編譯運行程序,相信你已經實現了開篇處展示的屬性表效果了吧!
以上代碼在Windows XP Sp3 + VS2005 + AE9.2環境下編譯通過。
本文實現的最終效果如下:
圖層標注實現起來并不復雜,本例僅做一個簡單示范,只加載AE的樣式庫,標注選定的字段,旨在拋磚引玉。更高級的功能,如自定義樣式和修改樣式,由讀者自己實現。
主要思路:
?加載圖層字段 –> 加載文本樣式 -> 設置文本樣式
實現過程:
?創建標注設置窗體 -> 創建圖層標注的Command -> 添加Command到圖層右鍵菜單
9.1創建標注設置窗體
(1)添加一個Windows窗體,命名為LabelLayerFrm.cs。添加控件如下:
控件
?Name屬性
?Text屬性
?其它
SymbologyControl
?axSymbologyControl
ComboBox
?cbbField
Button
?btnOK
?確定
?DialogResult設為OK
Button
?btnCancel
?取消
?DialogResult
設為Cancel
GroupBox
?groupBox1
?字段
GroupBox
?groupBox2
?符號
(2)為LabelLayerFrm類添加兩個成員變量:
public ILayer pLayer;
private IStyleGalleryItem pStyleGalleryItem;
(3)重載一個構造函數:
?public LabelLayerFrm(ILayer layer)
{
??? InitializeComponent();
??? pLayer = layer;
}
(4) 添加成員函數ReadRegistry,用于從注冊表中讀取ArcGIS的安裝路徑。
?/// <summary>
/// 讀取注冊表中的制定軟件的路徑
/// </summary>
/// <param name="sKey"></param>
/// <returns></returns>
private string ReadRegistry(string sKey)
{
??? //Open the subkey for reading
??? Microsoft.Win32.RegistryKey rk = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(sKey, true);
??? if (rk == null) return "";
??? // Get the data from a specified item in the key.
??? return (string)rk.GetValue("InstallDir");
}
(5)添加LabelLayerFrm窗體的Load事件,以加載圖層字段到下拉模型,加載文本樣式到SymbologyControl控件。
?private void LabelLayerFrm_Load(object sender, EventArgs e)
{
??? //加載圖層字段
??? ITable pTable = pLayer as ITable;
??? IField pField = null;
??? for (int i = 0; i < pTable.Fields.FieldCount; i++)
??? {
??????? pField = pTable.Fields.get_Field(i);
??????? cbbField.Items.Add(pField.AliasName);
??? }
??? cbbField.SelectedIndex = 0;
??? //獲得ArcGIS的安裝路徑
??? string sInstall = ReadRegistry("SOFTWARE\\ESRI\\CoreRuntime");
??? //加載ESRI.ServerStyle 樣式文件到SymbologyControl
??? this.axSymbologyControl1.LoadStyleFile(sInstall + "\\Styles\\ESRI.ServerStyle");
??? this.axSymbologyControl1.GetStyleClass(esriSymbologyStyleClass.esriStyleClassTextSymbols).SelectItem(0);
}
(6)添加axSymbologyControl1控件的OnItemSelected事件,以設置選定的樣式。
?private void axSymbologyControl1_OnItemSelected(object sender, ISymbologyControlEvents_OnItemSelectedEvent e)
{
??? pStyleGalleryItem = (IStyleGalleryItem)e.styleGalleryItem;
}
(7)添加確定按扭的Click事件,為選定圖層中的選定的字段以選定的樣式標注。
?private void btnOK_Click(object sender, EventArgs e)
{
??? IGeoFeatureLayer pGeoFeatureLayer = pLayer as IGeoFeatureLayer;
??? pGeoFeatureLayer.AnnotationProperties.Clear();//必須執行,因為里面有一個默認的
??? IBasicOverposterLayerProperties pBasic = new BasicOverposterLayerPropertiesClass();
??? ILabelEngineLayerProperties pLableEngine = new LabelEngineLayerPropertiesClass();
??? ITextSymbol pTextSymbol = new TextSymbolClass();???????????
??? pTextSymbol = (ITextSymbol)pStyleGalleryItem.Item;
??? //你可以在這里修改樣式的顏色和字體等屬性,本文從略
??? //pTextSymbol.Color
??? //pTextSymbol.Font
??? string pLable = "[" + (string)cbbField .SelectedItem + "]";
??? pLableEngine.Expression = pLable;
??? pLableEngine.IsExpressionSimple = true;
??? pBasic.NumLabelsOption = esriBasicNumLabelsOption.esriOneLabelPerShape;
? ??pLableEngine.BasicOverposterLayerProperties = pBasic;
??? pLableEngine.Symbol = pTextSymbol;
??? pGeoFeatureLayer.AnnotationProperties.Add(pLableEngine as IAnnotateLayerProperties);
??? pGeoFeatureLayer.DisplayAnnotation = true;
}
至此,標注設置窗體已經完成,如果你編譯通不過,看看是不是忘了添加相關引用了。
9.2創建圖層標注的Command
(1)創建一個新類,以ArcGIS的BaseCommand為模板,命名為LabelLayerCmd.cs。
注意:在新建Base Command模板時,會彈出一個對話框讓我們選擇模板適用對象,這時我們要選擇MapControl、PageLayoutControl,即選擇第二項或者倒數第二項。
(2)添加LabelLayerCmd類的成員變量。
?private ILayer pLayer = null;
IMapControl3 pMap;
(3)修改默認構造函數如下:
?public LabelLayerCmd(ILayer lyr,IMapControl3 map)
{
??? //
??? // TODO: Define values for the public properties
??? //
??? base.m_category = ""; //localizable text
??? base.m_caption = "標注";? //localizable text
??? base.m_message = "標注";? //localizable text
??? base.m_toolTip = "標注";? //localizable text
??? base.m_name = "標注";?? //unique id, non-localizable (e.g. "MyCategory_MyCommand")
??? pLayer = lyr;
??? pMap = map;
??? try
??? {
??????? //
??????? // TODO: change bitmap name if necessary
??????? //
??????? string bitmapResourceName = GetType().Name + ".bmp";
??????? base.m_bitmap = new Bitmap(GetType(), bitmapResourceName);
??? }
??? catch (Exception ex)
??? {
??????? System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap");
??? }
}
(4)修改OnClick函數為:
?/// <summary>
/// Occurs when this command is clicked
/// </summary>
public override void OnClick()
{
??? // TODO: Add LabelLayerCmd.OnClick implementation
??? LabelLayerFrm labelLyrFrm = new LabelLayerFrm(pLayer);
?? ?labelLyrFrm.ShowDialog();
??? pMap.Refresh(esriViewDrawPhase.esriViewGraphics, null, null);
}
9.3添加Command到圖層右鍵菜單
回到3sdnMap主窗體類,找到axTOCControl1_OnMouseDown事件響應函數,修改如下代碼片斷:
?//彈出右鍵菜單
if (item == esriTOCControlItem.esriTOCControlItemMap)
??? m_menuMap.PopupMenu(e.x, e.y, m_tocControl.hWnd);
if (item == esriTOCControlItem.esriTOCControlItemLayer)
{
m_menuLayer.AddItem(new OpenAttributeTable(layer), -1, 2, true , esriCommandStyles.esriCommandStyleTextOnly);
//動態添加圖層標注的Command到圖層右鍵菜單
??? m_menuLayer.AddItem(new LabelLayerCmd(layer, m_mapControl), -1, 3, false, esriCommandStyles.esriCommandStyleTextOnly);
??? //彈出圖層右鍵菜單
??? m_menuLayer.PopupMenu(e.x, e.y, m_tocControl.hWnd);
?//移除菜單項
??? m_menuLayer.Remove(3);
??? m_menuLayer.Remove(2);
}
至此,已經完成圖層文本標注,編譯運行吧,是不是看到開篇的效果了?
以上代碼在Windows XP Sp3 + VS2005 + AE9.2/9.3環境下編譯通過。
ArcEngine,C#數據刪除幾種方法和性能比較
By Yanleigis? Landgis@126.com
一、? 幾種刪除方法代碼
1.? 查詢結果中刪除
? private void Delete1(IFeatureClass PFeatureclass)
??????? {
??????????? IQueryFilter pQueryFilter = new QueryFilterClass();
??????????? pQueryFilter.WhereClause = "objectID<=" + DeleteNum;
??????????? IFeatureCursor pFeatureCursor = PFeatureclass.Search(pQueryFilter, false);??????????? IFeature pFeature = pFeatureCursor.NextFeature();
????????? ??while (pFeature != null)
??????????? {
??????????????? pFeature.Delete();
??????????????? pFeature = pFeatureCursor.NextFeature();
??????????? }
??????????? System.Runtime.InteropServices.Marshal.ReleaseComObject(pQueryFilter);
??????? }
2.? 更新游標刪除
private void Delete2(IFeatureClass PFeatureclass)
??????? {
??????????? IQueryFilter pQueryFilter = new QueryFilterClass();
??????????? pQueryFilter.WhereClause = "objectID<=" + DeleteNum;
??????????? IFeatureCursor pFeatureCursor = PFeatureclass.Update(pQueryFilter, false);
??????????? IFeature pFeature = pFeatureCursor.NextFeature();
??????????? while (pFeature != null)
??????????? {
??????????????? pFeatureCursor.DeleteFeature();
??????????????? pFeature = pFeatureCursor.NextFeature();
???? ???????}
??????????? System.Runtime.InteropServices.Marshal.ReleaseComObject(pQueryFilter);
??????? }
3.? 使用DeleteSearchedRows刪除
private void Delete4(IFeatureClass PFeatureclass)
??????? {
??????????? IQueryFilter pQueryFilter = new QueryFilterClass();
??????????? pQueryFilter.WhereClause = "objectID<=" + DeleteNum;
??????????? ITable pTable = PFeatureclass as ITable;
??????????? pTable.DeleteSearchedRows(pQueryFilter);
??????????? System.Runtime.InteropServices.Marshal.ReleaseComObject(pQueryFilter);
??????? }
4.? ExecuteSQL刪除
private void Delete4(IFeatureClass PFeatureclass)
??????? {
??????????? IDataset pDataset = PFeatureclass as IDataset;
??????????? pDataset.Workspace.ExecuteSQL("delete from " + PFeatureclass.AliasName + " where objectid<=" + DeleteNum);
??????? }
二、? 測試性能和比較
1、?????? 相同的數據條件,刪除2000條記錄
2、?????? 測試代碼
IFeatureLayer pFeatureLayer = axMapControl1.Map.get_Layer(0) as IFeatureLayer;
??????????? IFeatureClass PFeatureClass = pFeatureLayer.FeatureClass;
?????????? ?System.Diagnostics.Stopwatch MyWatch = new System.Diagnostics.Stopwatch();
??????????? MyWatch.Start();
??????????? Delete1(PFeatureClass)
??????????? //Delete2(PFeatureClass);
??????????? //Delete3(PFeatureClass);
??????????? //Delete4(PFeatureClass);
??????????? //Delete5(PFeatureClass);
??????????? MyWatch.Stop();
??????????? MessageBox.Show("刪除時間:" + MyWatch.ElapsedMilliseconds.ToString() + "毫秒");
3、?????? 測試情況
測試方法
?第一次時間(單位ms)
?第一次時間(單位ms)
1
?5214ms
?5735ms
2
?299ms
?290Ms
3
?59ms
?28ms
4
?26ms
?26ms
三、? 結論
1、???????? 使用ExecuteSQL刪除最快,數據庫的效率最高。
2、???????? DeleteSearchedRows和ExecuteSQL屬于批量刪除,性能較優。
3、???????? 查詢結果中刪除,速度最慢,如果你使用這種方法,建立你馬上修改你的程序,因為你在浪費時間。
4、?????? 小數據量記錄數小于500000條,請使用DeleteSearchedRows或ExecuteSQL,否則使用更新游標刪除(方法2),加上進度條,這樣界面很友好。
1 概述
緩沖區分析(Buffer)是對選中的一組或一類地圖要素(點、線或面)按設定的距離條件,圍繞其要素而形成一定緩沖區多邊形實體,從而實現數據在二維空間得以擴展的信息分析方法。緩沖區應用的實例有如:污染源對其周圍的污染量隨距離而減小,確定污染的區域;為失火建筑找到距其500米范圍內所有的消防水管等。
2 緩沖區的基礎
緩沖區是地理空間,目標的一種影響范圍或服務范圍在尺度上的表現。它是一種因變量,由所研究的要素的形態而發生改變。從數學的角度來看,緩沖區是給定空間對象或集合后獲得的它們的領域,而鄰域的大小由鄰域的半徑或緩沖區建立條件來決定,因此對于一個給定的對象A,它的緩沖區可以定義為:
P={x | d(x , A)<=r}
(d一般是指歐式距離,也可以是其它的距離,其中r為鄰域半徑或緩沖區建立的條件)
緩沖區建立的形態多種多樣,這是根據緩沖區建立的條件來確定的,常用的對于點狀要素有圓形,也有三角形、矩形和環形等;對于線狀要素有雙側對稱、雙側不對稱或單側緩沖區;對于面狀要素有內側和外側緩沖區,雖然這些形體各異,但是可以適合不同的應用要求,建立的原理都是一樣的。點狀要素,線狀要素和面狀要素的緩沖區示意圖如下。
3 定制工具的使用
1 打開工程GPBufferLayer\CSharp\GpBufferLayer.sln
2 在VS2005內選擇重新生成解決方案
3 開發需要添加工具的工程
4 在ToolBarControl上點右鍵,選擇屬性
5 選擇條目,點擊添加
6 在命令類中選擇“自定義工具集”,選擇“緩沖區分析”,可通過雙擊或者拖放到工具條上。
7 運行程序
8 使用“選擇要素”命令,選擇需要建立緩沖區的要素(點或線)
9 點擊工具條上的“緩沖區分析按鈕”,彈出緩沖區分析對話框
?????????????????? 選擇要素
選擇緩沖區分析按鈕
10 選擇緩存分析的圖層,選擇距離及單位,設置輸出的圖層
11 點擊分析按鈕,當出現“分析完成”字樣時,工作完成
12 這時通過附加新的圖層,即可看到結果
4 核心源代碼分析
4.1 BufferSelectedLayerCmd.cs
???? 主要完成定制command的相關代碼,具體原理可參見《ArcGIS Engine中文開發指南》
4.2 BufferDlg.cs
為緩沖區分析的輸入對話框。其中最主要的是“分析”按鈕的處理事件。源代碼及分析如下:
????? double bufferDistance;
??? //轉換distance為double類型
????? double.TryParse(txtBufferDistance.Text, out bufferDistance);
????? if (0.0 == bufferDistance)
????? {
??????? MessageBox.Show("Bad buffer distance!");
??????? return;
????? }
????? //判斷輸出路徑是否合法
????? if (!System.IO.Directory.Exists(System.IO.Path.GetDirectoryName(txtOutputPath.Text)) ||
??????? ".shp" != System.IO.Path.GetExtension(txtOutputPath.Text))
????? {
??????? MessageBox.Show("Bad output filename!");
??????? return;
????? }
????? //判斷圖層個數
????? if (m_hookHelper.FocusMap.LayerCount == 0)
??????? return;
????? //get the layer from the map
????? IFeatureLayer layer = GetFeatureLayer((string)cboLayers.SelectedItem);
????? if (null == layer)
????? {
??????? txtMessages.Text += "Layer " + (string)cboLayers.SelectedItem + "cannot be found!\r\n";
??????? return;
????? }
????? //scroll the textbox to the bottom
????? ScrollToBottom();
????? txtMessages.Text += "\r\n分析開始,這可能需要幾分鐘時間,請稍候..\r\n";
????? txtMessages.Update();
????? //get an instance of the geoprocessor
????? Geoprocessor gp = new Geoprocessor();
????? gp.OverwriteOutput = true;
??????? //create a new instance of a buffer tool
????? ESRI.ArcGIS.AnalysisTools.Buffer buffer = new ESRI.ArcGIS.AnalysisTools.Buffer(layer, txtOutputPath.Text, Convert.ToString(bufferDistance) + " " + (string)cboUnits.SelectedItem);
????? buffer.dissolve_option = "ALL";//這個要設成ALL,否則相交部分不會融合
????? //buffer.line_side = "FULL";//默認是"FULL",最好不要改否則出錯
????? //buffer.line_end_type = "ROUND";//默認是"ROUND",最好不要改否則出錯
?????
????? //execute the buffer tool (very easy :-))
????? IGeoProcessorResult results=null;
?????
????? try
????? {
????????? results = (IGeoProcessorResult)gp.Execute(buffer, null);
????? }
????? catch (Exception ex)
????? {
????????? txtMessages.Text += "Failed to buffer layer: " + layer.Name + "\r\n";
????? }
????? if (results.Status != esriJobStatus.esriJobSucceeded)
????? {
??????? txtMessages.Text += "Failed to buffer layer: " + layer.Name + "\r\n";
????? }
?????
?????? //scroll the textbox to the bottom
????? ScrollToBottom();
????? txtMessages.Text += "\r\n分析完成.\r\n";
????? txtMessages.Text += "-----------------------------------------------------------------------------------------\r\n";
????? //scroll the textbox to the bottom
????? ScrollToBottom();
轉載于:https://www.cnblogs.com/zhaokai417/archive/2011/03/03/1969825.html
總結
以上是生活随笔為你收集整理的arcgis开发常用源码的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数据仓库经验小结(转)
- 下一篇: telnet小技巧