diff --git a/DotNet.Exchange.Revit/DotNet.Exchange.Revit.csproj b/DotNet.Exchange.Revit/DotNet.Exchange.Revit.csproj new file mode 100644 index 0000000..86da647 --- /dev/null +++ b/DotNet.Exchange.Revit/DotNet.Exchange.Revit.csproj @@ -0,0 +1,69 @@ + + + + + Debug + AnyCPU + {22EDDE0F-0E6A-4C47-AEA5-17027830F236} + Library + Properties + DotNet.Exchange.Revit + DotNet.Exchange.Revit + v4.8 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + D:\Program Files\Autodesk\Revit 2016\RevitAPI.dll + False + + + D:\Program Files\Autodesk\Revit 2016\RevitAPIUI.dll + False + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/DotNet.Exchange.Revit/Export/ExportFactory.cs b/DotNet.Exchange.Revit/Export/ExportFactory.cs new file mode 100644 index 0000000..924365b --- /dev/null +++ b/DotNet.Exchange.Revit/Export/ExportFactory.cs @@ -0,0 +1,342 @@ +using Autodesk.Revit.DB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNet.Exchange.Revit.Export +{ + public class ExportFactory + { + #region fields + private uint m_ExportLevel; + private Document m_Document; + private IExportElement m_ExportHandle; + #endregion + + #region properties + /// + /// 导出等级. + /// 1 - 10;默认等级为5. + /// + public uint ExportLevel + { + get + { + return m_ExportLevel; + } + set + { + m_ExportLevel = value; + } + } + #endregion + + #region ctors + public ExportFactory(Document doc, IExportElement exportHandle) + { + if (exportHandle == null || doc == null) + throw new NullReferenceException("exportHandle or doc parameter is null reference !!"); + + m_ExportLevel = 5; + m_Document = doc; + m_ExportHandle = exportHandle; + } + #endregion + + #region methods + /// + /// 导出指定的元素 + /// + /// The elem array. + public void Export(params Element[] elemArray) + { + for (int i = 0; i < elemArray.Length; i++) + { + this.ElementExport(elemArray[i]); + } + } + + /// + /// 导出当前文档的所有元素. + /// + public void Export() + { + var view3d = new FilteredElementCollector(m_Document) + .OfClass(typeof(View3D)).FirstOrDefault(m => (m as View3D).Origin != null); + + if (view3d == null) + throw new NullReferenceException(); + + var elems = new FilteredElementCollector(m_Document, view3d.Id).WhereElementIsNotElementType(); + + var eum = elems.GetElementIterator(); + while (eum.MoveNext()) + { + this.ElementExport(eum.Current); + } + } + + /// + /// 异步导出指定元素. + /// + public void AsynchExport(params Element[] elemArray) + { + Task.Run(() => this.Export(elemArray)); + } + + /// + /// 异步导出当前文档所有元素. + /// + public void AsynchExport() + { + Task.Run(() => this.Export()); + } + + #endregion + + #region privates + + /// + /// Elements the export. + /// + private bool ElementExport(Element elem) + { + if (!m_ExportHandle.OnElementStart(elem)) + { + return false; + } + + var transform = default(Transform); + if (elem is Instance) + { + transform = (elem as Instance).GetTransform(); + } + + + var objects = this.GetGeometryObject(elem); + if (objects.Count == 0) + { + return false; + } + + while (objects.Count > 0) + { + var obj = objects.Pop(); + + var node = new GeometryObjectNode(obj); + if (!m_ExportHandle.OnGeometryObjectStart(node)) + { + return false; + } + + if (obj.GetType().Equals(typeof(Solid))) + { + var solid = obj as Solid; + + var faces = solid.Faces; + + var eum = faces.GetEnumerator(); + while (eum.MoveNext()) + { + var face = (Face)eum.Current; + + // not handle.... + m_ExportHandle.OnMaterial(face.MaterialElementId); + + var polygonMeshNode = this.FaceConvert(face, transform); + + m_ExportHandle.OnPolygonMesh(polygonMeshNode); + } + + } + m_ExportHandle.OnGeometryObjectEnd(node); + } + + m_ExportHandle.OnElementEnd(elem); + return true; + } + + + /// + /// Faces the convert. + /// + private PolygonMeshNode FaceConvert(Face face, Transform transform) + { + var result = new PolygonMeshNode(); + + var mesh = face.Triangulate(m_ExportLevel * 0.1); + var temps = new Dictionary(); + + // resolve triangle face.. + for (int i = 0; i < mesh.NumTriangles; i++) + { + var triangle = mesh.get_Triangle(i); + + var pt1 = triangle.get_Vertex(0); + var pt2 = triangle.get_Vertex(1); + var pt3 = triangle.get_Vertex(2); + + var pi1 = (int)triangle.get_Index(0); + var pi2 = (int)triangle.get_Index(1); + var pi3 = (int)triangle.get_Index(2); + + if (!temps.ContainsKey(pi1)) + { + temps.Add(pi1, pt1); + } + + if (!temps.ContainsKey(pi2)) + { + temps.Add(pi2, pt2); + } + + if (!temps.ContainsKey(pi3)) + { + temps.Add(pi3, pt3); + } + + result.TriangleFaces.Add(new TriangleFaceNode(pi1, pi2, pi3)); + } + + var eum = temps.OrderBy(m => m.Key).GetEnumerator(); + while (eum.MoveNext()) + { + result.Points.Add(eum.Current.Value); + } + + + // resolve point and uv.. + foreach (EdgeArray edgeArray in face.EdgeLoops) + { + foreach (Edge item in edgeArray) + { + result.AddUV(item.EvaluateOnFace(0, face)); + result.AddUV(item.EvaluateOnFace(1, face)); + } + } + + // resolve normal.. + + if (face.GetType().Equals(typeof(PlanarFace))) + { + var planarFace = face as PlanarFace; + result.AddNormal(planarFace.FaceNormal); + } + else + { + foreach (var item in result.TriangleFaces) + { + var normal = this.GetNormal(result.Points[item.V1], result.Points[item.V2], result.Points[item.V3]); + result.AddNormal(normal); + } + } + + if (transform != null) + { + for (int i = 0; i < result.Points.Count; i++) + { + result.Points[i] = transform.OfPoint(result.Points[i]); + } + + for (int i = 0; i < result.Normals.Count; i++) + { + result.Normals[i] = transform.OfVector(result.Normals[i]); + } + } + return result; + } + + public Autodesk.Revit.DB.Plane ToPlane(XYZ point, XYZ other) + { + var v = other - point; + var angle = v.AngleTo(XYZ.BasisX); + var norm = v.CrossProduct(XYZ.BasisX).Normalize(); + + if (Math.Abs(angle - 0) < 1e-4) + { + angle = v.AngleTo(XYZ.BasisY); + norm = v.CrossProduct(XYZ.BasisY).Normalize(); + } + + if (Math.Abs(angle - 0) < 1e-4) + { + angle = v.AngleTo(XYZ.BasisZ); + norm = v.CrossProduct(XYZ.BasisZ).Normalize(); + } + return new Autodesk.Revit.DB.Plane(norm, point); + } + + /// + /// Gets the normal. + /// + private XYZ GetNormal(XYZ p1, XYZ p2, XYZ p3) + { + var v1 = p2 - p1; + var v2 = p3 - p1; + return v1.CrossProduct(v2).Normalize(); + } + + /// + /// Gets the geometry object. + /// + private Stack GetGeometryObject(Element elem) + { + var geometryElement = default(GeometryElement); + + if (elem is FamilyInstance) + { + geometryElement = (elem as FamilyInstance).GetOriginalGeometry(new Options() { DetailLevel = ViewDetailLevel.Fine}); + } + else + { + geometryElement = elem.get_Geometry(new Options() { DetailLevel = ViewDetailLevel.Fine, ComputeReferences = true }); + } + + var objects = new List(); + this.RecursionObject(geometryElement, ref objects); + + return new Stack(objects); + } + + /// + /// Recursions the object. + /// + private void RecursionObject(GeometryElement geometryElement, ref List geometryObjects) + { + if (geometryElement == null) + return; + + var eum = geometryElement.GetEnumerator(); + while (eum.MoveNext()) + { + var current = eum.Current; + var type = current.GetType(); + + if (type.Equals(typeof(GeometryInstance))) + { + this.RecursionObject((current as GeometryInstance).SymbolGeometry, ref geometryObjects); + } + else if (type.Equals(typeof(GeometryElement))) + { + this.RecursionObject(current as GeometryElement, ref geometryObjects); + } + else + { + if (type.Equals(typeof(Solid))) + { + var solid = current as Solid; + if (solid.Edges.Size == 0 || solid.Faces.Size == 0) + { + continue; + } + } + geometryObjects.Add(current); + } + } + } + + #endregion + } +} diff --git a/DotNet.Exchange.Revit/Export/GeometryObjectNode.cs b/DotNet.Exchange.Revit/Export/GeometryObjectNode.cs new file mode 100644 index 0000000..89850da --- /dev/null +++ b/DotNet.Exchange.Revit/Export/GeometryObjectNode.cs @@ -0,0 +1,19 @@ +using Autodesk.Revit.DB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNet.Exchange.Revit.Export +{ + public class GeometryObjectNode + { + public GeometryObject GeometryObject { get; private set; } + + public GeometryObjectNode(GeometryObject geometryObject) + { + this.GeometryObject = geometryObject; + } + } +} diff --git a/DotNet.Exchange.Revit/Export/IExportElement.cs b/DotNet.Exchange.Revit/Export/IExportElement.cs new file mode 100644 index 0000000..7839a25 --- /dev/null +++ b/DotNet.Exchange.Revit/Export/IExportElement.cs @@ -0,0 +1,47 @@ +using Autodesk.Revit.DB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNet.Exchange.Revit.Export +{ + /// + /// IExportElement + /// + public interface IExportElement + { + /// + /// 元素开始进行导出时执行. + /// 如果返回结果为true,则开始进行此元素导出,否则放弃此元素导出. + /// + bool OnElementStart(Element elem); + + /// + /// 当元素内的GeometryObject进行导出时执行. + /// 如果返回结果为true,则开始进行此GeometryObject导出,否则放弃此元素导出. + /// + bool OnGeometryObjectStart(GeometryObjectNode geometryObject); + + /// + /// 开始检索多边形的材质. + /// + void OnMaterial(ElementId materialId); + + /// + /// 开始检索Solid内的多边形拓扑节点. + /// + void OnPolygonMesh(PolygonMeshNode polygonMesh); + + /// + /// 当元素内的GeometryObject导出结束时执行. + /// + void OnGeometryObjectEnd(GeometryObjectNode geometryObject); + + /// + /// 当元素导出结束时开始执行. + /// + void OnElementEnd(Element elem); + } +} diff --git a/DotNet.Exchange.Revit/Export/PolygonMeshNode.cs b/DotNet.Exchange.Revit/Export/PolygonMeshNode.cs new file mode 100644 index 0000000..54a3d6b --- /dev/null +++ b/DotNet.Exchange.Revit/Export/PolygonMeshNode.cs @@ -0,0 +1,52 @@ +using Autodesk.Revit.DB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNet.Exchange.Revit.Export +{ + public class PolygonMeshNode + { + public PolygonMeshNode() + { + this.Points = new List(); + this.TriangleFaces = new List(); + this.Normals = new List(); + this.UVs = new List(); + } + + public List Points { get; private set; } + public List TriangleFaces { get; private set; } + public List Normals { get; private set; } + public List UVs { get; private set; } + + internal void AddPoint(XYZ point) + { + var flag = this.Points.FirstOrDefault(m => m.IsAlmostEqualTo(point, 1e-6)); + if (flag == null) + { + this.Points.Add(point); + } + } + + internal void AddUV(UV uv) + { + var flag = this.UVs.FirstOrDefault(m => m.IsAlmostEqualTo(uv, 1e-6)); + if (flag == null) + { + this.UVs.Add(uv); + } + } + + internal void AddNormal(XYZ normal) + { + var flag = this.Normals.FirstOrDefault(m => m.IsAlmostEqualTo(normal, 1e-6)); + if (flag == null) + { + this.Normals.Add(normal); + } + } + } +} diff --git a/DotNet.Exchange.Revit/Export/TriangleFaceNode.cs b/DotNet.Exchange.Revit/Export/TriangleFaceNode.cs new file mode 100644 index 0000000..1f21364 --- /dev/null +++ b/DotNet.Exchange.Revit/Export/TriangleFaceNode.cs @@ -0,0 +1,23 @@ +using Autodesk.Revit.DB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNet.Exchange.Revit.Export +{ + public sealed class TriangleFaceNode + { + internal TriangleFaceNode(int v1, int v2, int v3) + { + this.V1 = (int)v1; + this.V2 = (int)v2; + this.V3 = (int)v3; + } + + public int V1 { get; private set; } + public int V2 { get; private set; } + public int V3 { get; private set; } + } +} diff --git a/DotNet.Exchange.Revit/ExportElment.cs b/DotNet.Exchange.Revit/ExportElment.cs new file mode 100644 index 0000000..996d2ca --- /dev/null +++ b/DotNet.Exchange.Revit/ExportElment.cs @@ -0,0 +1,51 @@ +using Autodesk.Revit.DB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNet.Exchange.Revit.Export +{ + /// + /// 自定义测试导出类. + /// + /// + public class ExportElment : IExportElement + { + // 临时测试 + + public HashSet PolygonMeshNodes = new HashSet(); + + bool IExportElement.OnElementStart(Autodesk.Revit.DB.Element elem) + { + + return true; + } + + bool IExportElement.OnGeometryObjectStart(GeometryObjectNode solid) + { + return true; + } + + void IExportElement.OnMaterial(Autodesk.Revit.DB.ElementId materialId) + { + + } + + void IExportElement.OnPolygonMesh(PolygonMeshNode polygonMesh) + { + PolygonMeshNodes.Add(polygonMesh); + } + + void IExportElement.OnGeometryObjectEnd(GeometryObjectNode solid) + { + + } + + void IExportElement.OnElementEnd(Autodesk.Revit.DB.Element elem) + { + + } + } +} diff --git a/DotNet.Exchange.Revit/Properties/AssemblyInfo.cs b/DotNet.Exchange.Revit/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..114c358 --- /dev/null +++ b/DotNet.Exchange.Revit/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DotNet.Exchange.Revit")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DotNet.Exchange.Revit")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ec829d77-42ee-431c-8606-4c23ab9123fd")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/DotNet.Exchange.Revit/Test.cs b/DotNet.Exchange.Revit/Test.cs new file mode 100644 index 0000000..9f549be --- /dev/null +++ b/DotNet.Exchange.Revit/Test.cs @@ -0,0 +1,135 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; +using Autodesk.Revit.Utility; +using System.Diagnostics; +using Autodesk.Revit.ApplicationServices; +using DotNet.Exchange.Revit.Export; + +namespace DotNet.Exchange.Revit +{ + /// + /// 自定义导出测试代码。 + /// 备注:自定义导出未经过长时间测试,在此开源是提供一个思路和方法,如果有遇到问题,可联系本人进行讨论. + /// + /// + [Transaction(TransactionMode.Manual)] + public class Test : IExternalCommand + { + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) + { + var uiDoc = commandData.Application.ActiveUIDocument; + + var doc = uiDoc.Document; + + var refer = uiDoc.Selection.PickObject(Autodesk.Revit.UI.Selection.ObjectType.Element); + + var elem = doc.GetElement(refer); + + + var export = new ExportElment(); + var exportFactory = new ExportFactory(doc, export); + exportFactory.ExportLevel = 3; + exportFactory.Export(elem); + + // 绘制测试,因绘制线速度较慢,所以当需要绘制测试时,请测试少量模型 + + doc.Invoke(m => + { + foreach (var polygonMesh in export.PolygonMeshNodes) + { + foreach (var triangleFaces in polygonMesh.TriangleFaces) + { + var p1 = polygonMesh.Points[triangleFaces.V1]; + var p2 = polygonMesh.Points[triangleFaces.V2]; + var p3 = polygonMesh.Points[triangleFaces.V3]; + + CreateModelLine(doc, p1, p2); + CreateModelLine(doc, p2, p3); + CreateModelLine(doc, p3, p1); + } + } + }); + return Result.Succeeded; + } + + private void CreateModelLine(Document doc, XYZ p1, XYZ p2) + { + using (var line = Line.CreateBound(p1, p2)) + { + using (var skPlane = SketchPlane.Create(doc, this.ToPlane(p1, p2))) + { + if (doc.IsFamilyDocument) + { + doc.FamilyCreate.NewModelCurve(line, skPlane); + } + else + { + doc.Create.NewModelCurve(line, skPlane); + } + } + } + } + + private Autodesk.Revit.DB.Plane ToPlane(XYZ point, XYZ other) + { + var v = other - point; + var angle = v.AngleTo(XYZ.BasisX); + var norm = v.CrossProduct(XYZ.BasisX).Normalize(); + + if (Math.Abs(angle - 0) < 1e-4) + { + angle = v.AngleTo(XYZ.BasisY); + norm = v.CrossProduct(XYZ.BasisY).Normalize(); + } + + if (Math.Abs(angle - 0) < 1e-4) + { + angle = v.AngleTo(XYZ.BasisZ); + norm = v.CrossProduct(XYZ.BasisZ).Normalize(); + } + return new Autodesk.Revit.DB.Plane(norm, point); + } + } + + public static class DocumentExtension + { + /// + /// 使用委托启动事务.事务内自动进行事务启动,提交、回滚等处理。 + /// + /// The document. + /// The action. + /// The name. + public static void Invoke(this Document doc, Action action, string name = "default") + { + using (var tr = new Transaction(doc, name)) + { + tr.Start(); + + action(tr); + + var status = tr.GetStatus(); + switch (status) + { + case TransactionStatus.Started: + tr.Commit(); + return; + case TransactionStatus.Committed: + case TransactionStatus.RolledBack: + break; + case TransactionStatus.Error: + tr.RollBack(); + return; + default: + return; + } + } + } + } +} + diff --git a/DotNet.Revit.ExternalEvent/CmdExternalEvent.cs b/DotNet.Revit.ExternalEvent/CmdExternalEvent.cs new file mode 100644 index 0000000..2d0cede --- /dev/null +++ b/DotNet.Revit.ExternalEvent/CmdExternalEvent.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; +using Autodesk.Revit.Attributes; +using DotNet.Revit.ExternalEvent; +using System.Windows.Interop; +using Autodesk.Windows; + +namespace DotNet.Revit.ExternalEvent +{ + [Transaction(TransactionMode.Manual)] + public class CmdExternalEvent : IExternalCommand + { + private static CmdExternalEvent m_Instance; + private ExternalEventHelper m_ExternalEventHelper; + + public static CmdExternalEvent Instance + { + get { return m_Instance; } + } + + public ExternalEventHelper ExternalEventHelper + { + get { return m_ExternalEventHelper; } + } + + + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elements) + { + m_Instance = this; + m_ExternalEventHelper = new ExternalEventHelper(commandData.Application); + + + var main = new MainWinodow(); + var mainHelper = new WindowInteropHelper(main); + mainHelper.Owner = ComponentManager.ApplicationWindow; + main.Show(); + + return Result.Succeeded; + } + + } + +} diff --git a/DotNet.Revit.ExternalEvent/DocumentExtension.cs b/DotNet.Revit.ExternalEvent/DocumentExtension.cs new file mode 100644 index 0000000..105b170 --- /dev/null +++ b/DotNet.Revit.ExternalEvent/DocumentExtension.cs @@ -0,0 +1,24 @@ +using Autodesk.Revit.DB; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNet.Revit.ExternalEvent +{ + public static class DocumentExtension + { + public static void Invoke(this Document doc, Action action, string name = "INVOKE") + { + using (var tr = new Transaction(doc, name)) + { + tr.Start(); + action(tr); + + if (tr.GetStatus() == TransactionStatus.Started) + tr.Commit(); + } + } + } +} diff --git a/DotNet.Revit.ExternalEvent/DotNet.Revit.ExternalEvent.csproj b/DotNet.Revit.ExternalEvent/DotNet.Revit.ExternalEvent.csproj new file mode 100644 index 0000000..6429655 --- /dev/null +++ b/DotNet.Revit.ExternalEvent/DotNet.Revit.ExternalEvent.csproj @@ -0,0 +1,80 @@ + + + + + Debug + AnyCPU + {7164311A-01C1-4FAB-97DB-B9310C973800} + Library + Properties + DotNet.Revit.ExternalEvent + DotNet.Revit.ExternalEvent + v4.8 + 512 + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + False + ..\..\..\..\CYBIM\CYCommons\References\Revit\16\AdWindows.dll + False + + + + + ..\..\..\..\CYBIM\CYCommons\References\Revit\16\RevitAPI.dll + + + ..\..\..\..\CYBIM\CYCommons\References\Revit\16\RevitAPIUI.dll + + + + + + + + + + + + + + + + + MainWinodow.xaml + + + + + + Designer + MSBuild:Compile + + + + + \ No newline at end of file diff --git a/DotNet.Revit.ExternalEvent/ExternalEventHelper.cs b/DotNet.Revit.ExternalEvent/ExternalEventHelper.cs new file mode 100644 index 0000000..50e9d1e --- /dev/null +++ b/DotNet.Revit.ExternalEvent/ExternalEventHelper.cs @@ -0,0 +1,124 @@ +using Autodesk.Revit.UI; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotNet.Revit.ExternalEvent +{ + /// + /// 外部事件的封装. + /// + public class ExternalEventHelper + { + private readonly ExternalEventHandlerCommon externalEventHandlerCommon; + + private readonly Autodesk.Revit.UI.ExternalEvent externalEvent; + + /// + /// 外部事件刚刚开始并且准备执行时触发. + /// + public event EventHandler Started; + + /// + /// 外部事件结束时触发. + /// + public event EventHandler End; + + public ExternalEventHelper(UIApplication uiApp) + { + this.externalEventHandlerCommon = new ExternalEventHandlerCommon(); + this.externalEvent = Autodesk.Revit.UI.ExternalEvent.Create(this.externalEventHandlerCommon); + + this.externalEventHandlerCommon.Started += externalEventCommon_Started; + this.externalEventHandlerCommon.End += externalEventCommon_End; + } + + public ExternalEventHelper(UIControlledApplication uiControlApp) + { + this.externalEventHandlerCommon = new ExternalEventHandlerCommon(); + this.externalEvent = Autodesk.Revit.UI.ExternalEvent.Create(this.externalEventHandlerCommon); + + this.externalEventHandlerCommon.Started += externalEventCommon_Started; + this.externalEventHandlerCommon.End += externalEventCommon_End; + } + + public void Invoke(Action action, string name = "") + { + var nf = string.IsNullOrWhiteSpace(name) ? Guid.NewGuid().ToString() : name; + this.externalEventHandlerCommon.Actions.Enqueue(new KeyValuePair>(nf, action)); + this.externalEvent.Raise(); + } + + private void externalEventCommon_End(object sender, ExternalEventArg e) + { + if (this.End != null) + this.End(this, e); + } + + private void externalEventCommon_Started(object sender, ExternalEventArg e) + { + if (this.Started != null) + this.Started(this, e); + } + + class ExternalEventHandlerCommon : IExternalEventHandler + { + internal Queue>> Actions { get; set; } + + public event EventHandler Started; + public event EventHandler End; + + internal ExternalEventHandlerCommon() + { + this.Actions = new Queue>>(); + } + + public void Execute(UIApplication app) + { + while (this.Actions.Count > 0) + { + var first = this.Actions.Dequeue(); + + if (string.IsNullOrWhiteSpace(first.Key) || first.Value == null) + continue; + + try + { + if (this.Started != null) + this.Started(this, new ExternalEventArg(app, first.Key)); + + first.Value(app); + } + finally + { + this.End(this, new ExternalEventArg(app, first.Key)); + } + } + } + + public string GetName() + { + return ""; + } + } + } + + /// + /// 外部事件参数. + /// + /// + public class ExternalEventArg : EventArgs + { + public ExternalEventArg(UIApplication app, string name) + { + this.App = app; + this.Name = name; + } + + public UIApplication App { get; private set; } + + public string Name { get; private set; } + } +} diff --git a/DotNet.Revit.ExternalEvent/MainWinodow.xaml b/DotNet.Revit.ExternalEvent/MainWinodow.xaml new file mode 100644 index 0000000..f9ddc29 --- /dev/null +++ b/DotNet.Revit.ExternalEvent/MainWinodow.xaml @@ -0,0 +1,12 @@ + + + + + + + diff --git a/Test.DotNet.RevitUI (2016)/View/MainDeleteMatchElement.xaml.cs b/Test.DotNet.RevitUI (2016)/View/MainDeleteMatchElement.xaml.cs new file mode 100644 index 0000000..ceccbab --- /dev/null +++ b/Test.DotNet.RevitUI (2016)/View/MainDeleteMatchElement.xaml.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using DotNet.RevitUI.MVVM; +using Test.DotNet.RevitUI.ViewModel; + +namespace Test.DotNet.RevitUI.View +{ + /// + /// MainSplitWall.xaml 的交互逻辑 + /// + public partial class MainDeleteMatchElement : Window + { + internal const string ClosedToken = "ClosedToken"; + + public MainDeleteMatchElement() + { + InitializeComponent(); + + Messenger.Default.Register(this, ClosedToken, m => this.Close()); + } + } +} diff --git a/Test.DotNet.RevitUI (2016)/View/RibbonView.xaml b/Test.DotNet.RevitUI (2016)/View/RibbonView.xaml new file mode 100644 index 0000000..42d9a7c --- /dev/null +++ b/Test.DotNet.RevitUI (2016)/View/RibbonView.xaml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Test.DotNet.RevitUI (2016)/View/RibbonView.xaml.cs b/Test.DotNet.RevitUI (2016)/View/RibbonView.xaml.cs new file mode 100644 index 0000000..b2185cd --- /dev/null +++ b/Test.DotNet.RevitUI (2016)/View/RibbonView.xaml.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; +using Test.DotNet.RevitUI.ViewModel; + +namespace Test.DotNet.RevitUI.View +{ + /// + /// RibbonView.xaml 的交互逻辑 + /// + public partial class RibbonView : UserControl + { + public RibbonView() + { + InitializeComponent(); + + this.DataContext = new RibbonViewModel(); + } + } +} diff --git a/Test.DotNet.RevitUI (2016)/ViewModel/DeleteElementViewModel.cs b/Test.DotNet.RevitUI (2016)/ViewModel/DeleteElementViewModel.cs new file mode 100644 index 0000000..5f43fb3 --- /dev/null +++ b/Test.DotNet.RevitUI (2016)/ViewModel/DeleteElementViewModel.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Autodesk.Revit.UI; +using DotNet.RevitUI; +using DotNet.RevitUI.MVVM; +using Test.DotNet.RevitUI.View; + +namespace Test.DotNet.RevitUI.ViewModel +{ + public class DeleteElementViewModel : ObservableObject + { + private int _elementId; + + public int ElementId + { + get + { + return _elementId; + } + + set + { + _elementId = value; + + this.RaisePropertyChanged(nameof(ElementId)); + } + } + + /// + /// Revit动态委托命令 + /// + /// 也可以直接绑定RevitCommand + public RevitRelayCommand OK { get; private set; } + + public RelayCommand Cancel { get; private set; } + + public DeleteElementViewModel() + { + this.ElementId = 0; + + this.OK = new RevitRelayCommand(OnOK, () => ElementId > 0); + + this.Cancel = new RelayCommand(OnCancel); + } + + private void OnCancel() + { + Messenger.Default.Send(this, MainDeleteMatchElement.ClosedToken); + } + + private Result OnOK(ExternalCommandData arg) + { + var uidoc = arg.Application.ActiveUIDocument; + + var doc = uidoc.Document; + + if (doc.GetElement(new Autodesk.Revit.DB.ElementId(ElementId)) is Autodesk.Revit.DB.Element elem) + { + doc.Invoke(m => + { + try + { + doc.Delete(elem.Id); + } + catch (Exception ex) + { + Autodesk.Revit.UI.TaskDialog.Show("错误", ex.Message); + } + }); + + Autodesk.Revit.UI.TaskDialog.Show("提示", "删除元素完成"); + + return Result.Succeeded; + } + + Autodesk.Revit.UI.TaskDialog.Show("警告", "输入元素ID不合法,或者未在当前文档找到此元素ID"); + + return Result.Succeeded; + } + } +} diff --git a/Test.DotNet.RevitUI (2016)/ViewModel/RibbonViewModel.cs b/Test.DotNet.RevitUI (2016)/ViewModel/RibbonViewModel.cs new file mode 100644 index 0000000..1e25db7 --- /dev/null +++ b/Test.DotNet.RevitUI (2016)/ViewModel/RibbonViewModel.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using DotNet.RevitUI; +using DotNet.RevitUI.MVVM; +using Test.DotNet.RevitUI.Command; + +namespace Test.DotNet.RevitUI.ViewModel +{ + public class RibbonViewModel : ObservableObject + { + /// + /// 删除元素 测试 + /// + + public RevitCommand DeleteElement { get; set; } + + /// + /// 删除匹配元素 测试 + /// + public RevitCommand DeleteMatchElement { get; set; } + + /// + /// This is command test + /// + public RevitCommand SplitButton1 { get; set; } + + /// + /// This is command test + /// + public RevitCommand SplitButton2 { get; set; } + + /// + /// This is command test + /// + public RevitCommand FlowButton1 { get; set; } + + /// + /// This is command test + /// + public RevitCommand FlowButton2 { get; set; } + + + public RibbonViewModel() + { + this.DeleteElement = new DeleteElementCommand(); + + this.DeleteMatchElement = new DeleteMatchElementCommand(); + + this.SplitButton1 = new SplitButton1Command(); + + this.SplitButton2 = new SplitButton1Command(); + + this.FlowButton1 = new FlowButton1Command(); + + this.FlowButton2 = new FlowButton1Command(); + } + } +}