一、ArcGIS10新特性
1、 在ArcGIS10中新增了要素附件功能。要素附件即:在FeatureClass中的每一个Feature都可以关联一个或多个任意格式附件文件(如,文档文件、图片和视频文件等)。另一方面,在数据库中,如果删除了featureClass则与之对应要素附件也会被删除。
2、 ArcGIS中的要素附件管理的原理。
(1) 创建要素附件。
在ArcGIS10中,只能为要素类(FeatureClass)创建附件(即:一个要素类对应一个附件表和一个关系类)。具体创建方法见下图1:
图1 为要素类(图中为DISTR)创建附件。
创建附件后,会在数据库中自动创建一个表(Table)和关系类(RelationshhipClass),如下图2所示:
图2要素类DISTR及其附件表(DISTR_ATTACH)和关系类(DISTR_ATTACHREL)
(2) 添加附件。
在ArcMap中,加载已经创建了附件的要素图层,开启编辑,即可为每一个要素添加附件。如下图3和图4所示:
图3添加附件
图4添加任意格式的附件
(3) 查询附件。
在ArcMap中进行要素属性查询时,如果要素存在附件,可以再要素属性查询窗口中看到,如下图5所示:
图5 要素属性查询
(4) 附件表和关系类
附件表结构和关系类如下图6、7所示:
图6附件表
图7关系类
3、 ArcGIS10中新增的接口:ITableAttachments
(1) OMD图
(2) ITableAttachments、IAttachmentManager、IEnumAttachment、IAttachment等接口相关属性和方法,可以参考开发帮助
二、自定义实现要素附件管理(适用于ArcGIS 9.3和ArcGIS10)
尽管ArcGIS10提供了附件管理功能,但是在使用的时候并不是很方便,主要原因是:
1、只能只对一个要素类进行管理,即:一个要素类对应一个附件表和关系类。如果要对所有的要素类进行附件管理,就需要为每一个要素创建一个附件表和关系类,不能进行统一管理。
2、受版本限制,目前只能在ArcGIS10及以上版本中使用这个功能,对于10之前的版本就无能为力了。
鉴于上面的原因,我们可以基于ArcGIS10的附件管理原理,自定义实现要素的附件管理功能,这样我们可以突破限制,对所有的要素类的附件进行统一管理同时不受版本的限制(目前已经测试在10和9.3中均适用)。实现的过程比较简单,具体的方法:
在数据库中创建一个附件表,所有要素类和所有的附件都存放在这个附件表中,在增、删、查的时候只要操作这个附件表就行了。具体的表结构设计:
附件表
下面不多说了,贴代码:
public interface ISMFeatureAttachment { void SMAddAttachments();//添加附件表 bool SMHasAttachments{get;}//判断是否存在附件表 void SMDeleteAttachments();//删除附件表 ISMAttachmentManager SMAttachmentManager { get; }//附件管理接口 } public interface ISMAttachmentManager { bool SMAddAttachment(ISMAttachment attachment);//添加附件 bool SMAddAttachment2(ISMAttachment attachment);//添加附件 bool SMDeleteAttachment(int attachmentID);//删除指定附件ID的附件 bool SMDeleteAttachmentForFeature(int featureID,string physicalLayerName);//删除指定要素的所有附件 void SMUpdateAttachment(ISMAttachment attachment);//更新附件 ISMEnumAttachment GetAttachmentByParentID(int featureID,bool IsOnlyInfo);//获取指定要素的所有附件 //ISMAttachment GetAttachmentByAttachmentID(int attachmentID);//获取指定附件ID的附件 IWorkspace Workspace { get; set; }//工作空间属性 string AttachmentTableName { get; set; }//附件表名属性 } public interface ISMAttachment { int AttachmentID { get; set; } int ParentID { get; set; } string ContentType { get; set; } IMemoryBlobStream Data { get; set; } uint DataSize { get; } string AttachmentName { get; set; } string PhysicalLayerName { get; set; } } public interface ISMEnumAttachment { ISMAttachment Next(); void Reset(); IWorkspace CurrentWorkspace{get;set;} ITable AttachmentTable{get;set;} List<ISMAttachment> AttachmentList { get;} }
/// <summary>
/// 摘要:附件管理器
/// </summary>
public class SMAttachmentManagerClass:ISMAttachmentManager
{
private int m_FeatureID;
private IWorkspace m_Workspace;
private string m_AttachmentTableName;
/// <summary>
/// 构造函数
/// </summary>
public SMAttachmentManagerClass()
{
}#region ISMAttachmentManager 成员
/// <summary>
/// 添加附件
/// </summary>
/// <param name="featureID">要素ID</param>
/// <param name="attachment">附件对象</param>
public bool SMAddAttachment(ISMAttachment attachment)
{
try
{
//打开附件表
ITable pTable = (this.Workspace as IFeatureWorkspace).OpenTable(this.m_AttachmentTableName);
IRow pRow = pTable.CreateRow();
IFields fields = pRow.Fields;
for (int i = 0; i < fields.FieldCount; i++)
{
IField field = pTable.Fields.get_Field(i);
if (field.Name.ToUpper() == "OBJECTID") continue;
switch (field.Name.ToUpper())
{
case "PARENTID":
pRow.set_Value(i, attachment.ParentID);
break;
case "ATTACHMENTNAME":
pRow.set_Value(i, attachment.AttachmentName);
break;
case "CONTENTTYPE":
pRow.set_Value(i, attachment.ContentType.ToString());
break;
case "DATA":
pRow.set_Value(i,(object)attachment.Data);
break;
case "DATASIZE":
pRow.set_Value(i,attachment.DataSize);
break;
case "PHYSICALLAYERNAME":
pRow.set_Value(i,attachment.PhysicalLayerName);
break;
default:
break;
}
}
pRow.Store();
return true;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// 添加附件
/// </summary>
/// <param name="attachment">附件</param>
/// <returns></returns>
public bool SMAddAttachment2(ISMAttachment attachment)
{
IRowBuffer rowBuffer = null;
ICursor insertCursor = null;
try
{
IWorkspaceEdit pWSEdit = this.Workspace as IWorkspaceEdit;
//打开附件表
ITable pTable = (this.Workspace as IFeatureWorkspace).OpenTable(this.m_AttachmentTableName);
IFields fields = pTable.Fields;
pWSEdit.StartEditing(true);
pWSEdit.StartEditOperation();rowBuffer = pTable.CreateRowBuffer();
insertCursor = pTable.Insert(true);for (int i = 0; i < fields.FieldCount; i++)
{
IField field = rowBuffer.Fields.get_Field(i);
if (field.Name.ToUpper() == "OBJECTID") continue;
switch (field.Name.ToUpper())
{
case "PARENTID":
rowBuffer.set_Value(i, attachment.ParentID);
break;
case "ATTACHMENTNAME":
rowBuffer.set_Value(i, attachment.AttachmentName);
break;
case "CONTENTTYPE":
rowBuffer.set_Value(i, attachment.ContentType.ToString());
break;
case "DATA":
rowBuffer.set_Value(i, attachment.Data);
break;
case "DATASIZE":
rowBuffer.set_Value(i, attachment.DataSize);
break;
case "PHYSICALLAYERNAME":
rowBuffer.set_Value(i, attachment.PhysicalLayerName);
break;
default:
break;
}
}
insertCursor.InsertRow(rowBuffer);
insertCursor.Flush();
pWSEdit.StopEditOperation();
pWSEdit.StopEditing(true);
return true;
}
catch (Exception)
{
return false;
}
finally
{
if (rowBuffer != null) { System.Runtime.InteropServices.Marshal.ReleaseComObject(rowBuffer); }
if (insertCursor != null) { System.Runtime.InteropServices.Marshal.ReleaseComObject(insertCursor); }
}
}/// <summary>
/// 删除指定附件
/// </summary>
/// <param name="attachmentID"></param>
public bool SMDeleteAttachment(int attachmentID)
{
string whereClause = string.Format("objectID={0}", attachmentID);
DeletRows(whereClause);
return true;
}/// <summary>
/// 删除要素的所有附件
/// </summary>
/// <param name="featureID"></param>
public bool SMDeleteAttachmentForFeature(int featureID,string physicalLayerName)
{
string whereClause = string.Format("ParentID={0} and PhysicalLayerName='{1}'",featureID,physicalLayerName);
DeletRows(whereClause);
return true;
}/// <summary>
/// 更新附件
/// </summary>
/// <param name="attachment"></param>
public void SMUpdateAttachment(ISMAttachment attachment)
{
//删除原始附件记录
string WhereClause = string.Format("OBJECTID={0}",attachment.AttachmentID);
DeletRows(WhereClause);
//添加附件
SMAddAttachment(attachment);
}/// <summary>
/// 获取指定要素的所有附件
/// </summary>
/// <param name="featureID">要素ID</param>
/// <returns></returns>
public ISMEnumAttachment GetAttachmentByParentID(int featureID, bool IsOnlyInfo)
{
ITable pTable = (this.Workspace as IFeatureWorkspace).OpenTable(this.m_AttachmentTableName);
ISMEnumAttachment enumAttachment = new SMEnumAttachmentClass(featureID,IsOnlyInfo,this.Workspace,pTable);
return enumAttachment;
}/// <summary>
/// 工作空间
/// </summary>
public IWorkspace Workspace
{
get
{
return this.m_Workspace;
}
set
{
this.m_Workspace = value;
}
}/// <summary>
/// 附件表名
/// </summary>
public string AttachmentTableName
{
get
{
return this.m_AttachmentTableName;
}
set
{
this.m_AttachmentTableName = value;
}
}
#endregion/// <summary>
/// 快速删除表中的行对象
/// </summary>
/// <param name="whereClause"></param>
private void DeletRows(string whereClause)
{
try
{
ITable pTable = (this.Workspace as IFeatureWorkspace).OpenTable(this.m_AttachmentTableName);
IQueryFilter pQueryFilter = new QueryFilterClass();
pQueryFilter.WhereClause = whereClause;pTable.DeleteSearchedRows(pQueryFilter);//快速删除
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show("异常来自:SMDeleteAttachment:\r\n" + ex.Message);
}
}
}public class SMAttachmentClass:ISMAttachment
{
private IFeature m_Feature;//要素
private int m_AttachmentID;//附件ID
private int m_ParentID;//要素ID
private string m_ContentType;//附件内容类型
private IMemoryBlobStream m_Data;//附件
private uint m_DataSize;//附件大小
private string m_AttachmentName;//附件名称
private string m_PhysicalLayerName;//物理图层名
public SMAttachmentClass()
{}
#region ISMAttachment 成员
/// <summary>
/// 附件ID
/// </summary>
public int AttachmentID
{
get { return this.m_AttachmentID; }
set { this.m_AttachmentID = value;}
}
/// <summary>
/// 要素ID
/// </summary>
public int ParentID
{
get
{
return this.m_ParentID;
}
set
{
this.m_ParentID=value;
}
}
/// <summary>
/// 附件类型
/// </summary>
public string ContentType
{
get
{
return this.m_ContentType;
}
set
{
this.m_ContentType = value;
}
}
/// <summary>
/// 附件数据
/// </summary>
public ESRI.ArcGIS.esriSystem.IMemoryBlobStream Data
{
get
{
return this.m_Data;
}
set
{
this.m_Data=value;
}
}
/// <summary>
/// 附件大小
/// </summary>
public uint DataSize
{
get { return this.m_Data.Size; }
}
/// <summary>
/// 附件名称
/// </summary>
public string AttachmentName
{
get
{
return this.m_AttachmentName;
}
set
{
this.m_AttachmentName=value;
}
}
/// <summary>
/// 物理图层名
/// </summary>
public string PhysicalLayerName
{
get
{
return this.m_PhysicalLayerName;
}
set
{
this.m_PhysicalLayerName = value;
}
}
#endregion
}public class SMFeatureAttachmentClass:ISMFeatureAttachment
{
private IWorkspace m_Workspace;
private string m_TableName;
private ISMAttachmentManager m_AttachmentManager;/// <summary>
/// 构造函数
/// </summary>
/// <param name="ws"></param>
/// <param name="tablename"></param>
public SMFeatureAttachmentClass(IWorkspace ws,string tablename)
{
this.m_Workspace=ws;
this.m_TableName = tablename;//附件表名
}#region ISMFeatureAttachment 成员
/// <summary>
/// 添加要素附件表
/// </summary>
public void SMAddAttachments()
{
try
{
if (this.SMHasAttachments)
{
MessageBox.Show(string.Format("要素附件表【{0}】已经存在。", this.m_TableName), "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
else
{
IFields fields = this.CreateFiledCollectionForTable();//字段集合
if (fields != null)
{
if (this.CreateAttachmentTable(this.m_Workspace, this.m_TableName, fields))
{
MessageBox.Show(string.Format("要素附件表【{0}】创建成功.", this.m_TableName), "信息提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
else
{
MessageBox.Show(string.Format("要素附件表【{0}】创建失败.", this.m_TableName), "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else
{
MessageBox.Show("初始化字段集合失败!");
}
}
}
catch (Exception ex)
{
MessageBox.Show(string.Format("要素附件表【{0}】创建失败。原因:\r\n"+ex.Message, this.m_TableName), "错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
/// <summary>
/// 检查附件表是否存在
/// </summary>
public bool SMHasAttachments
{
get
{
IWorkspace2 ws2 = this.m_Workspace as IWorkspace2;
if (ws2.get_NameExists(esriDatasetType.esriDTTable, this.m_TableName))
{
return true;
}
else
{
return false;
}
}
}
/// <summary>
/// 删除附件表
/// </summary>
public void SMDeleteAttachments()
{
DeleteAttachmentTable(this.m_TableName);//删除附件表
}
/// <summary>
/// 附件管理器
/// </summary>
public ISMAttachmentManager SMAttachmentManager
{
get
{
if (this.m_AttachmentManager == null)
{
this.m_AttachmentManager = new SMAttachmentManagerClass();
m_AttachmentManager.Workspace = this.m_Workspace;
m_AttachmentManager.AttachmentTableName = this.m_TableName;
}
return this.m_AttachmentManager;
}
}
#endregion#region 辅助函数
/// <summary>
/// 创建附件表
/// </summary>
/// <param name="tablename">表名</param>
private bool CreateAttachmentTable(IWorkspace workspace,string tablename,IFields fields)
{
try
{
IFeatureWorkspace featureWorkspace = (IFeatureWorkspace)workspace;
IObjectClassDescription ocDescription = new ObjectClassDescriptionClass();IFieldChecker fieldChecker = new FieldCheckerClass();
IEnumFieldError enumFieldError = null;
IFields validatedFields = null;
fieldChecker.ValidateWorkspace = workspace;
fieldChecker.Validate(fields, out enumFieldError, out validatedFields);ITable table = featureWorkspace.CreateTable(tablename, validatedFields,
ocDescription.InstanceCLSID, null, "");
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 创建字段集合
/// </summary>
private IFields CreateFiledCollectionForTable()
{
IFields pFields = new FieldsClass();
IFieldsEdit pFieldsEdit = pFields as IFieldsEdit;
IField pField = null;//AttachmentID
pField = new FieldClass();
IFieldEdit pFieldEdit = pField as IFieldEdit;
pFieldEdit.Name_2 = "AttachmentID";
pFieldEdit.AliasName_2 = "附件ID";
pFieldEdit.Type_2 = esriFieldType.esriFieldTypeOID;
pFieldsEdit.AddField(pField);
//ParentID
pField = new FieldClass();
IFieldEdit parentField = pField as IFieldEdit;
parentField.Type_2 = esriFieldType.esriFieldTypeInteger;
parentField.Name_2 = "ParentID";
parentField.AliasName_2 = "要素ID";
parentField.IsNullable_2 = false;
pFieldsEdit.AddField(pField);
//AttachmentName
pField = new FieldClass();
IFieldEdit nameField = pField as IFieldEdit;
nameField.Type_2 = esriFieldType.esriFieldTypeString;
nameField.Name_2 = "AttachmentName";
nameField.AliasName_2 = "附件名称";
nameField.IsNullable_2 = false;
pFieldsEdit.AddField(pField);
//ContentType
pField = new FieldClass();
IFieldEdit contentField = pField as IFieldEdit;
contentField.Type_2 = esriFieldType.esriFieldTypeString;
contentField.Name_2 = "ContentType";
contentField.AliasName_2 = "附件类型";
contentField.IsNullable_2 = false;
pFieldsEdit.AddField(pField);
//Data
pField = new FieldClass();
IFieldEdit dataField = pField as IFieldEdit;
dataField.Type_2 = esriFieldType.esriFieldTypeBlob;
dataField.Name_2 = "Data";
dataField.AliasName_2 = "附件数据";
dataField.IsNullable_2 = false;
pFieldsEdit.AddField(pField);
//DataSize
pField = new FieldClass();
IFieldEdit datasizeField = pField as IFieldEdit;
datasizeField.Type_2 = esriFieldType.esriFieldTypeInteger;
datasizeField.Name_2 = "DataSize";
datasizeField.AliasName_2 = "附件大小";
datasizeField.IsNullable_2 = false;
pFieldsEdit.AddField(pField);
//PhysicalLayerName
pField = new FieldClass();
IFieldEdit layerField = pField as IFieldEdit;
layerField.Type_2 = esriFieldType.esriFieldTypeString;
layerField.Name_2 = "PhysicalLayerName";
layerField.AliasName_2 = "物理图层名";
layerField.IsNullable_2 = false;
pFieldsEdit.AddField(pField);return pFields;
}
/// <summary>
/// 删除附件表
/// </summary>
/// <param name="tablename">表名</param>
private void DeleteAttachmentTable(string tablename)
{
if (this.SMHasAttachments)
{
try
{
if (MessageBox.Show(string.Format("确定要删除附件表【{0}】吗?", this.m_TableName), "", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
{
ITable pTable = (this.m_Workspace as IFeatureWorkspace).OpenTable(this.m_TableName);
ISchemaLock schemaLock = pTable as ISchemaLock;