|
发表于 2011-11-5 08:12:21
|
显示全部楼层
嗨,
这是属性提取的小例子。
我尝试使用Linq扩展方法和扩展类中定义的其他一些方法以“声明性”风格编写它(感谢Thorsten 'kaefer' @ TheSwamp的“邪恶”方法)。
提取收集在 System.Data.DataTable 中,以便可以轻松地将其转换为 AutoCAD 表、Exel 工作表等。
DataTable.WriteXls() 扩展方法在与 Excel 应用程序交互时使用后期绑定,以避免版本引用依赖关系。
BlockAttribute 类,它定义了一个新类型,其主要属性为:
- Block:块(有效)名称 ;
- 属性:块属性的字典,其中Key是标签,Value是文本字符串。
BlockAttributeEqualityComparer 类实现了 IEqualityComparer
接口,以便 BlockAttribute 集合可以与某些 Linq 扩展方法一起使用,如 GroupBy()。
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using Autodesk.AutoCAD.ApplicationServices;
- using Autodesk.AutoCAD.DatabaseServices;
- using AcAp = Autodesk.AutoCAD.ApplicationServices.Application;
- namespace AttributeExtraction
- {
- public class BlockAttribute
- {
- private string _name;
- private Dictionary _atts;
- // Public read only properties
- public string Name
- {
- get { return _name; }
- }
- public Dictionary Attributes
- {
- get { return _atts; }
- }
- public string this[string key]
- {
- get { return _atts[key.ToUpper()]; }
- }
- // Constructors
- public BlockAttribute(BlockReference br)
- {
- SetProperties(br);
- }
- public BlockAttribute(ObjectId id)
- {
- Document doc = AcAp.DocumentManager.MdiActiveDocument;
- using (Transaction tr = doc.TransactionManager.StartTransaction())
- {
- SetProperties(tr.GetObject(id, OpenMode.ForRead) as BlockReference);
- }
- }
- // Public method
- new public string ToString()
- {
- if (_atts != null && _atts.Count > 0)
- return string.Format("{0}: {1}",
- _name,
- _atts.Select(a => string.Format("{0}={1}", a.Key, a.Value))
- .Aggregate((a, b) => string.Format("{0}; {1}", a, b)));
- return _name;
- }
- // Private method
- private void SetProperties(BlockReference br)
- {
- if (br == null) return;
- _name = br.GetEffectiveName();
- _atts = new Dictionary();
- br.AttributeCollection
- .GetObjects()
- .Iterate(att => _atts.Add(att.Tag.ToUpper(), att.TextString));
- }
- }
- public class BlockAttributeEqualityComparer : IEqualityComparer[B]
- {
- public bool Equals(BlockAttribute x, BlockAttribute y)
- {
- return
- x.Name.Equals(y.Name, StringComparison.CurrentCultureIgnoreCase) &&
- x.Attributes.SequenceEqual(y.Attributes);
- }
- public int GetHashCode(BlockAttribute obj)
- {
- return base.GetHashCode();
- }
- }
- }
扩展类提供了扩展方法,允许以更“声明性”的风格编写代码
,并提供从BlockAttribute集合构建DataTable并将此DataTable转换为xls,csv文件或AutoCAD表的方法。
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Data;
- using System.IO;
- using System.Linq;
- using Autodesk.AutoCAD.DatabaseServices;
- using AcDataTable = Autodesk.AutoCAD.DatabaseServices.DataTable;
- namespace AttributeExtraction
- {
- public static class Extensions
- {
- // Opens a DBObject in ForRead mode (kaefer @ TheSwamp)
- public static T GetObject(this ObjectId id) where T : DBObject
- {
- return id.GetObject(OpenMode.ForRead);
- }
- // Opens a DBObject in the given mode (kaefer @ TheSwamp)
- public static T GetObject(this ObjectId id, OpenMode mode) where T : DBObject
- {
- return id.GetObject(mode) as T;
- }
-
- // Opens a collection of DBObject in ForRead mode (kaefer @ TheSwamp)
- public static IEnumerable GetObjects(this IEnumerable ids) where T : DBObject
- {
- return ids.GetObjects(OpenMode.ForRead);
- }
- // Opens a collection of DBObject in the given mode (kaefer @ TheSwamp)
- public static IEnumerable GetObjects(this IEnumerable ids, OpenMode mode) where T : DBObject
- {
- return ids
- .Cast()
- .Select(id => id.GetObject(mode))
- .Where(res => res != null);
- }
- // Applies the given Action to each element of the collection (mimics the F# Seq.iter function).
- public static void Iterate(this IEnumerable collection, Action action)
- {
- foreach (T item in collection) action(item);
- }
- // Applies the given Action to each element of the collection (mimics the F# Seq.iteri function).
- // The integer passed to the Action indicates the index of element.
- public static void Iterate(this IEnumerable collection, Action action)
- {
- int i = 0;
- foreach (T item in collection) action(item, i++);
- }
- // Gets the block effective name (anonymous dynamic blocs).
- public static string GetEffectiveName(this BlockReference br)
- {
- if (br.IsDynamicBlock)
- return br.DynamicBlockTableRecord.GetObject[B]().Name;
- return br.Name;
- }
- // Creates a System.Data.DataTable from a BlockAttribute collection.
- public static System.Data.DataTable ToDataTable(this IEnumerable[B] blockAtts, string name)
- {
- System.Data.DataTable dTable = new System.Data.DataTable(name);
- dTable.Columns.Add("Name", typeof(string));
- dTable.Columns.Add("Quantity", typeof(int));
- blockAtts
- .GroupBy(blk => blk, (blk, blks) => new { Block = blk, Count = blks.Count() }, new BlockAttributeEqualityComparer())
- .Iterate(row =>
- {
- System.Data.DataRow dRow = dTable.Rows.Add(row.Block.Name, row.Count);
- row.Block.Attributes.Iterate(att =>
- {
- if (!dTable.Columns.Contains(att.Key))
- dTable.Columns.Add(att.Key);
- dRow[att.Key] = att.Value;
- });
- });
- return dTable;
- }
- // Gets the column names collection of the datatable
- public static IEnumerable GetColumnNames(this System.Data.DataTable dataTbl)
- {
- return dataTbl.Columns.Cast().Select(col => col.ColumnName);
- }
- // Writes an Excel file from the datatable (using late binding)
- public static void WriteXls(this System.Data.DataTable dataTbl, string filename, string sheetName, bool visible)
- {
- object mis = Type.Missing;
- object xlApp = LateBinding.GetOrCreateInstance("Excel.Application");
- xlApp.Set("DisplayAlerts", false);
- object workbooks = xlApp.Get("Workbooks");
- object workbook, worksheet;
- if (File.Exists(filename))
- workbook = workbooks.Invoke("Open", filename);
- else
- workbook = workbooks.Invoke("Add", mis);
- if (string.IsNullOrEmpty(sheetName))
- worksheet = workbook.Get("Activesheet");
- else
- {
- object worksheets = workbook.Get("Worksheets");
- try
- {
- worksheet = worksheets.Get("Item", sheetName);
- worksheet.Get("Cells").Invoke("Clear");
- }
- catch
- {
- worksheet = worksheets.Invoke("Add", mis);
- worksheet.Set("Name", sheetName);
- }
- }
- object range = worksheet.Get("Cells");
- dataTbl.GetColumnNames()
- .Iterate((name, i) => range.Get("Item", 1, i + 1).Set("Value2", name));
- dataTbl.Rows
- .Cast()
- .Iterate((row, i) => row.ItemArray
- .Iterate((item, j) => range.Get("Item", i + 2, j + 1).Set("Value2", item)));
- xlApp.Set("DisplayAlerts", true);
|
|