diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..4bb21ee
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,150 @@
+root = true
+# EditorConfig is awesome:http://EditorConfig.org
+
+# top-most EditorConfig file
+
+# Don't use tabs for indentation.
+[*]
+indent_style = space
+indent_size = 2
+
+# Code files
+[*.{cs, csx, vb, vbx}]
+insert_final_newline = true
+charset = utf-8-bom
+
+# ReSharper properties
+resharper_csharp_extra_spaces = leave_multiple
+resharper_csharp_naming_rule.private_constants = AaBb, AA_BB
+resharper_csharp_space_within_array_access_brackets = true
+resharper_space_around_arrow_op = true
+resharper_space_within_array_rank_brackets = true
+resharper_use_indent_from_vs = false
+resharper_xml_attribute_style = first_attribute_on_single_line
+resharper_xml_pi_attribute_style = first_attribute_on_single_line
+
+# Dotnet code style settings:
+[*.{cs, vb}]
+# Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = true
+# Avoid "this." and "Me." if not necessary
+dotnet_style_qualification_for_field = false : suggestion
+dotnet_style_qualification_for_property = false : suggestion
+dotnet_style_qualification_for_method = false : suggestion
+dotnet_style_qualification_for_event = false : suggestion
+
+# Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true : suggestion
+dotnet_style_predefined_type_for_member_access = true : suggestion
+
+# Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+
+# CSharp code style settings:
+[*.cs]
+# Prefer "var" everywhere
+csharp_style_var_for_built_in_types = true : suggestion
+csharp_style_var_when_type_is_apparent = true : suggestion
+csharp_style_var_elsewhere = true : suggestion
+
+# Prefer method-like constructs to have a block body
+csharp_style_expression_bodied_methods = false:none
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_operators = false:none
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:none
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
+
+# Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true : suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true : suggestion
+csharp_style_inlined_variable_declaration = true : suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true : suggestion
+
+# Newline settings
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+
+spaces_around_brackets = inside
+csharp_using_directive_placement = outside_namespace:silent
+csharp_prefer_simple_using_statement = true:suggestion
+csharp_prefer_braces = true:silent
+csharp_style_namespace_declarations = block_scoped:silent
+csharp_style_prefer_method_group_conversion = true:silent
+csharp_style_prefer_top_level_statements = true:silent
+csharp_style_expression_bodied_lambdas = true:silent
+csharp_style_expression_bodied_local_functions = false:silent
+csharp_style_prefer_null_check_over_type_check = true:suggestion
+csharp_indent_labels = one_less_than_current
+
+[*.{cs,vb}]
+#### Naming styles ####
+
+# Naming rules
+
+dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion
+dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface
+dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i
+
+dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.types_should_be_pascal_case.symbols = types
+dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case
+
+dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members
+dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case
+
+# Symbol specifications
+
+dotnet_naming_symbols.interface.applicable_kinds = interface
+dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.interface.required_modifiers =
+
+dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum
+dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.types.required_modifiers =
+
+dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method
+dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected
+dotnet_naming_symbols.non_field_members.required_modifiers =
+
+# Naming styles
+
+dotnet_naming_style.begins_with_i.required_prefix = I
+dotnet_naming_style.begins_with_i.required_suffix =
+dotnet_naming_style.begins_with_i.word_separator =
+dotnet_naming_style.begins_with_i.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+
+dotnet_naming_style.pascal_case.required_prefix =
+dotnet_naming_style.pascal_case.required_suffix =
+dotnet_naming_style.pascal_case.word_separator =
+dotnet_naming_style.pascal_case.capitalization = pascal_case
+dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
+dotnet_style_prefer_auto_properties = true:silent
+dotnet_style_prefer_simplified_boolean_expressions = true:suggestion
+dotnet_style_prefer_conditional_expression_over_assignment = true:silent
+dotnet_style_prefer_conditional_expression_over_return = true:silent
+dotnet_style_prefer_inferred_tuple_names = true:suggestion
+dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
+dotnet_style_prefer_compound_assignment = true:suggestion
+dotnet_style_prefer_simplified_interpolation = true:suggestion
+dotnet_style_namespace_match_folder = true:suggestion
+dotnet_style_operator_placement_when_wrapping = beginning_of_line
+tab_width = 2
+end_of_line = crlf
diff --git a/Directory.Build.props b/Directory.Build.props
index d15da13..cfd1aeb 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -63,6 +63,7 @@
+
diff --git a/xUnitRevit.sln b/xUnitRevit.sln
index 3712a5a..0697209 100644
--- a/xUnitRevit.sln
+++ b/xUnitRevit.sln
@@ -19,6 +19,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "xUnitRevitUtils2022", "xUni
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{F5A2849D-7C58-4894-B9C5-8488E244B7CF}"
ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props
EndProjectSection
EndProject
diff --git a/xUnitRevitUtils2019/xUnitRevitUtils2019.csproj b/xUnitRevitUtils2019/xUnitRevitUtils2019.csproj
index 718399b..fd2d743 100644
--- a/xUnitRevitUtils2019/xUnitRevitUtils2019.csproj
+++ b/xUnitRevitUtils2019/xUnitRevitUtils2019.csproj
@@ -6,10 +6,6 @@
xUnitRevitUtils.2019
-
-
-
-
diff --git a/xUnitRevitUtils2020/xUnitRevitUtils2020.csproj b/xUnitRevitUtils2020/xUnitRevitUtils2020.csproj
index 5215545..176555a 100644
--- a/xUnitRevitUtils2020/xUnitRevitUtils2020.csproj
+++ b/xUnitRevitUtils2020/xUnitRevitUtils2020.csproj
@@ -6,9 +6,6 @@
xUnitRevitUtils.2020
-
-
-
diff --git a/xUnitRevitUtils2021/xUnitRevitUtils2021.csproj b/xUnitRevitUtils2021/xUnitRevitUtils2021.csproj
index 5543811..027df3c 100644
--- a/xUnitRevitUtils2021/xUnitRevitUtils2021.csproj
+++ b/xUnitRevitUtils2021/xUnitRevitUtils2021.csproj
@@ -6,6 +6,7 @@
xUnitRevitUtils.2021
+
diff --git a/xUnitRevitUtils2021/xru.cs b/xUnitRevitUtils2021/xru.cs
deleted file mode 100644
index 4351a1e..0000000
--- a/xUnitRevitUtils2021/xru.cs
+++ /dev/null
@@ -1,159 +0,0 @@
-using Autodesk.Revit.DB;
-using Autodesk.Revit.UI;
-using Xunit;
-
-namespace xUnitRevitUtils {
- ///
- /// Utility class with methods and properties used by the xUnit Revit plugin
- ///
- public static class xru {
- public static UIApplication Uiapp { get; set; }
-
- private static IList Queue { get; set; }
- private static ExternalEvent EventHandler { get; set; }
-
- public static SynchronizationContext UiContext { get; set; }
-
- public static void Initialize(UIApplication uiapp, SynchronizationContext uiContext, ExternalEvent eventHandler, IList queue) {
- Uiapp = uiapp;
- UiContext = uiContext;
- EventHandler = eventHandler;
- Queue = queue;
- }
-
- #region utility methods
-
- ///
- /// Returns the selected elements in the active document
- ///
- ///
- public static IList GetActiveSelection() {
- Assert.NotNull(Uiapp);
-
- if (Uiapp.ActiveUIDocument != null)
- return Uiapp.ActiveUIDocument.Selection.GetElementIds().Select(x => Uiapp.ActiveUIDocument.Document.GetElement(x)).ToList();
- return new List();
- }
- ///
- /// Opens and activates a document if not open already
- ///
- /// Path to the file to open
- public static Document OpenDoc(string filePath) {
- Assert.NotNull(Uiapp);
- Document doc = null;
- //OpenAndActivateDocument only works if run from the current context
- UiContext.Send(x => { doc = Uiapp.OpenAndActivateDocument(filePath).Document; }, null);
- Assert.NotNull(doc);
- return doc;
- }
-
- ///
- /// Creates a new empty document
- ///
- /// Path to the project template
- /// Path where to save the new doc
- /// If true overwrites existing files with same name
- ///
- public static Document CreateNewDoc(string templatePath, string filePath, bool overwrite = true) {
- Assert.NotNull(Uiapp);
- Document doc = null;
-
- try {
- if (overwrite && File.Exists(filePath))
- File.Delete(filePath);
- }
- catch { }
-
- //OpenAndActivateDocument only works if run from the current context
- UiContext.Send(x => {
- //if already open, just use it
- if (!File.Exists(filePath)) {
- doc = Uiapp.Application.NewProjectDocument(templatePath);
- doc.SaveAs(filePath);
- doc.Close();
- }
-
- doc = Uiapp.OpenAndActivateDocument(filePath).Document;
- }
- , null);
- Assert.NotNull(doc);
- return doc;
- }
-
- ///
- /// Runs an Action in a Revit transaction, uses TaskCompletionSource to communicate when done
- ///
- /// Action to run
- /// Revit Document
- /// Transaction Name
- /// Enable to swallow all warnings generated by the transaction and prevent them from being raised within Revit
- ///
- public static Task RunInTransaction(Action action, Document doc, string transactionName = "transaction", bool ignoreWarnings = false) {
- var tcs = new TaskCompletionSource();
- Queue.Add(new Action(() => {
- try {
- using (Transaction transaction = new Transaction(doc, transactionName)) {
- transaction.Start();
-
- if (ignoreWarnings) {
- var options = transaction.GetFailureHandlingOptions();
- options.SetFailuresPreprocessor(new IgnoreAllWarnings());
- transaction.SetFailureHandlingOptions(options);
- }
-
- action.Invoke();
- transaction.Commit();
- }
- }
- catch (Exception e) {
- tcs.TrySetException(e);
- }
- tcs.TrySetResult("");
- }));
-
- EventHandler.Raise();
-
- return tcs.Task;
- }
-
- ///
- /// Runs an Action, uses TaskCompletionSource to communicate when done
- ///
- /// Action to run
- /// Revit Document
- ///
- public static Task Run(Action action, Document doc) {
- var tcs = new TaskCompletionSource();
- Queue.Add(new Action(() => {
- try {
- action.Invoke();
- }
- catch (Exception e) {
- tcs.TrySetException(e);
- }
- tcs.TrySetResult("");
- }));
-
- EventHandler.Raise();
-
- return tcs.Task;
- }
-
- ///
- /// A failures preprocesser that clears any failures that occur within a transaction
- ///
- internal class IgnoreAllWarnings : IFailuresPreprocessor {
- public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) {
- var failList = failuresAccessor.GetFailureMessages();
-
- foreach (FailureMessageAccessor failure in failList) {
- failuresAccessor.DeleteWarning(failure);
- }
-
- return FailureProcessingResult.Continue;
- }
- }
-
- #endregion
- }
-}
diff --git a/xUnitRevitUtils2022/xUnitRevitUtils2022.csproj b/xUnitRevitUtils2022/xUnitRevitUtils2022.csproj
index e369953..7a6968c 100644
--- a/xUnitRevitUtils2022/xUnitRevitUtils2022.csproj
+++ b/xUnitRevitUtils2022/xUnitRevitUtils2022.csproj
@@ -6,8 +6,9 @@
xUnitRevitUtils.2022
+
-
+
diff --git a/xUnitRevitUtils2023/xUnitRevitUtils2023.csproj b/xUnitRevitUtils2023/xUnitRevitUtils2023.csproj
index 05e9220..b27d4a4 100644
--- a/xUnitRevitUtils2023/xUnitRevitUtils2023.csproj
+++ b/xUnitRevitUtils2023/xUnitRevitUtils2023.csproj
@@ -6,8 +6,9 @@
xUnitRevitUtils.2023
+
-
+
diff --git a/xUnitRevitUtils2023/xru.cs b/xUnitRevitUtils2023/xru.cs
deleted file mode 100644
index 0c2869e..0000000
--- a/xUnitRevitUtils2023/xru.cs
+++ /dev/null
@@ -1,155 +0,0 @@
-using Autodesk.Revit.DB;
-using Autodesk.Revit.UI;
-using Xunit;
-
-namespace xUnitRevitUtils {
- ///
- /// Utility class with methods and properties used by the xUnit Revit plugin
- ///
- public static class xru {
- public static UIApplication Uiapp { get; set; }
- private static IList Queue { get; set; }
- private static ExternalEvent EventHandler { get; set; }
- public static SynchronizationContext UiContext { get; set; }
- public static void Initialize(UIApplication uiapp, SynchronizationContext uiContext, ExternalEvent eventHandler, IList queue) {
- Uiapp = uiapp;
- UiContext = uiContext;
- EventHandler = eventHandler;
- Queue = queue;
- }
-
- #region utility methods
-
- ///
- /// Returns the selected elements in the active document
- ///
- ///
- public static IList GetActiveSelection() {
- Assert.NotNull(Uiapp);
-
- if (Uiapp.ActiveUIDocument != null)
- return Uiapp.ActiveUIDocument.Selection.GetElementIds().Select(x => Uiapp.ActiveUIDocument.Document.GetElement(x)).ToList();
- return new List();
- }
- ///
- /// Opens and activates a document if not open already
- ///
- /// Path to the file to open
- public static Document OpenDoc(string filePath) {
- Assert.NotNull(Uiapp);
- Document doc = null;
- //OpenAndActivateDocument only works if run from the current context
- UiContext.Send(x => { doc = Uiapp.OpenAndActivateDocument(filePath).Document; }, null);
- Assert.NotNull(doc);
- return doc;
- }
-
- ///
- /// Creates a new empty document
- ///
- /// Path to the project template
- /// Path where to save the new doc
- /// If true overwrites existing files with same name
- ///
- public static Document CreateNewDoc(string templatePath, string filePath, bool overwrite = true) {
- Assert.NotNull(Uiapp);
- Document doc = null;
-
- try {
- if (overwrite && File.Exists(filePath))
- File.Delete(filePath);
- }
- catch { }
-
- //OpenAndActivateDocument only works if run from the current context
- UiContext.Send(x => {
- //if already open, just use it
- if (!File.Exists(filePath)) {
- doc = Uiapp.Application.NewProjectDocument(templatePath);
- doc.SaveAs(filePath);
- doc.Close();
- }
-
- doc = Uiapp.OpenAndActivateDocument(filePath).Document;
- }
- , null);
- Assert.NotNull(doc);
- return doc;
- }
-
- ///
- /// Runs an Action in a Revit transaction, uses TaskCompletionSource to communicate when done
- ///
- /// Action to run
- /// Revit Document
- /// Transaction Name
- /// Enable to swallow all warnings generated by the transaction and prevent them from being raised within Revit
- ///
- public static Task RunInTransaction(Action action, Document doc, string transactionName = "transaction", bool ignoreWarnings = false) {
- var tcs = new TaskCompletionSource();
- Queue.Add(new Action(() => {
- try {
- using (Transaction transaction = new Transaction(doc, transactionName)) {
- transaction.Start();
-
- if (ignoreWarnings) {
- var options = transaction.GetFailureHandlingOptions();
- options.SetFailuresPreprocessor(new IgnoreAllWarnings());
- transaction.SetFailureHandlingOptions(options);
- }
-
- action.Invoke();
- transaction.Commit();
- }
- }
- catch (Exception e) {
- tcs.TrySetException(e);
- }
- tcs.TrySetResult("");
- }));
-
- EventHandler.Raise();
-
- return tcs.Task;
- }
-
- ///
- /// Runs an Action, uses TaskCompletionSource to communicate when done
- ///
- /// Action to run
- /// Revit Document
- ///
- public static Task Run(Action action, Document doc) {
- var tcs = new TaskCompletionSource();
- Queue.Add(new Action(() => {
- try {
- action.Invoke();
- }
- catch (Exception e) {
- tcs.TrySetException(e);
- }
- tcs.TrySetResult("");
- }));
-
- EventHandler.Raise();
-
- return tcs.Task;
- }
-
- ///
- /// A failures preprocesser that clears any failures that occur within a transaction
- ///
- internal class IgnoreAllWarnings : IFailuresPreprocessor {
- public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) {
- var failList = failuresAccessor.GetFailureMessages();
-
- foreach (FailureMessageAccessor failure in failList) {
- failuresAccessor.DeleteWarning(failure);
- }
-
- return FailureProcessingResult.Continue;
- }
- }
- #endregion
- }
-}
diff --git a/xUnitRevitUtils2022/xru.cs b/xUnitRevitUtilsShared/xru.cs
similarity index 97%
rename from xUnitRevitUtils2022/xru.cs
rename to xUnitRevitUtilsShared/xru.cs
index 0c2869e..66384ff 100644
--- a/xUnitRevitUtils2022/xru.cs
+++ b/xUnitRevitUtilsShared/xru.cs
@@ -1,155 +1,155 @@
-using Autodesk.Revit.DB;
-using Autodesk.Revit.UI;
-using Xunit;
-
-namespace xUnitRevitUtils {
- ///
- /// Utility class with methods and properties used by the xUnit Revit plugin
- ///
- public static class xru {
- public static UIApplication Uiapp { get; set; }
- private static IList Queue { get; set; }
- private static ExternalEvent EventHandler { get; set; }
- public static SynchronizationContext UiContext { get; set; }
- public static void Initialize(UIApplication uiapp, SynchronizationContext uiContext, ExternalEvent eventHandler, IList queue) {
- Uiapp = uiapp;
- UiContext = uiContext;
- EventHandler = eventHandler;
- Queue = queue;
- }
-
- #region utility methods
-
- ///
- /// Returns the selected elements in the active document
- ///
- ///
- public static IList GetActiveSelection() {
- Assert.NotNull(Uiapp);
-
- if (Uiapp.ActiveUIDocument != null)
- return Uiapp.ActiveUIDocument.Selection.GetElementIds().Select(x => Uiapp.ActiveUIDocument.Document.GetElement(x)).ToList();
- return new List();
- }
- ///
- /// Opens and activates a document if not open already
- ///
- /// Path to the file to open
- public static Document OpenDoc(string filePath) {
- Assert.NotNull(Uiapp);
- Document doc = null;
- //OpenAndActivateDocument only works if run from the current context
- UiContext.Send(x => { doc = Uiapp.OpenAndActivateDocument(filePath).Document; }, null);
- Assert.NotNull(doc);
- return doc;
- }
-
- ///
- /// Creates a new empty document
- ///
- /// Path to the project template
- /// Path where to save the new doc
- /// If true overwrites existing files with same name
- ///
- public static Document CreateNewDoc(string templatePath, string filePath, bool overwrite = true) {
- Assert.NotNull(Uiapp);
- Document doc = null;
-
- try {
- if (overwrite && File.Exists(filePath))
- File.Delete(filePath);
- }
- catch { }
-
- //OpenAndActivateDocument only works if run from the current context
- UiContext.Send(x => {
- //if already open, just use it
- if (!File.Exists(filePath)) {
- doc = Uiapp.Application.NewProjectDocument(templatePath);
- doc.SaveAs(filePath);
- doc.Close();
- }
-
- doc = Uiapp.OpenAndActivateDocument(filePath).Document;
- }
- , null);
- Assert.NotNull(doc);
- return doc;
- }
-
- ///
- /// Runs an Action in a Revit transaction, uses TaskCompletionSource to communicate when done
- ///
- /// Action to run
- /// Revit Document
- /// Transaction Name
- /// Enable to swallow all warnings generated by the transaction and prevent them from being raised within Revit
- ///
- public static Task RunInTransaction(Action action, Document doc, string transactionName = "transaction", bool ignoreWarnings = false) {
- var tcs = new TaskCompletionSource();
- Queue.Add(new Action(() => {
- try {
- using (Transaction transaction = new Transaction(doc, transactionName)) {
- transaction.Start();
-
- if (ignoreWarnings) {
- var options = transaction.GetFailureHandlingOptions();
- options.SetFailuresPreprocessor(new IgnoreAllWarnings());
- transaction.SetFailureHandlingOptions(options);
- }
-
- action.Invoke();
- transaction.Commit();
- }
- }
- catch (Exception e) {
- tcs.TrySetException(e);
- }
- tcs.TrySetResult("");
- }));
-
- EventHandler.Raise();
-
- return tcs.Task;
- }
-
- ///
- /// Runs an Action, uses TaskCompletionSource to communicate when done
- ///
- /// Action to run
- /// Revit Document
- ///
- public static Task Run(Action action, Document doc) {
- var tcs = new TaskCompletionSource();
- Queue.Add(new Action(() => {
- try {
- action.Invoke();
- }
- catch (Exception e) {
- tcs.TrySetException(e);
- }
- tcs.TrySetResult("");
- }));
-
- EventHandler.Raise();
-
- return tcs.Task;
- }
-
- ///
- /// A failures preprocesser that clears any failures that occur within a transaction
- ///
- internal class IgnoreAllWarnings : IFailuresPreprocessor {
- public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) {
- var failList = failuresAccessor.GetFailureMessages();
-
- foreach (FailureMessageAccessor failure in failList) {
- failuresAccessor.DeleteWarning(failure);
- }
-
- return FailureProcessingResult.Continue;
- }
- }
- #endregion
- }
-}
+using Autodesk.Revit.DB;
+using Autodesk.Revit.UI;
+using Xunit;
+
+namespace xUnitRevitUtils {
+ ///
+ /// Utility class with methods and properties used by the xUnit Revit plugin
+ ///
+ public static class xru {
+ public static UIApplication Uiapp { get; set; }
+ private static IList Queue { get; set; }
+ private static ExternalEvent EventHandler { get; set; }
+ public static SynchronizationContext UiContext { get; set; }
+ public static void Initialize(UIApplication uiapp, SynchronizationContext uiContext, ExternalEvent eventHandler, IList queue) {
+ Uiapp = uiapp;
+ UiContext = uiContext;
+ EventHandler = eventHandler;
+ Queue = queue;
+ }
+
+ #region utility methods
+
+ ///
+ /// Returns the selected elements in the active document
+ ///
+ ///
+ public static IList GetActiveSelection() {
+ Assert.NotNull(Uiapp);
+
+ if (Uiapp.ActiveUIDocument != null)
+ return Uiapp.ActiveUIDocument.Selection.GetElementIds().Select(x => Uiapp.ActiveUIDocument.Document.GetElement(x)).ToList();
+ return new List();
+ }
+ ///
+ /// Opens and activates a document if not open already
+ ///
+ /// Path to the file to open
+ public static Document OpenDoc(string filePath) {
+ Assert.NotNull(Uiapp);
+ Document doc = null;
+ //OpenAndActivateDocument only works if run from the current context
+ UiContext.Send(x => { doc = Uiapp.OpenAndActivateDocument(filePath).Document; }, null);
+ Assert.NotNull(doc);
+ return doc;
+ }
+
+ ///
+ /// Creates a new empty document
+ ///
+ /// Path to the project template
+ /// Path where to save the new doc
+ /// If true overwrites existing files with same name
+ ///
+ public static Document CreateNewDoc(string templatePath, string filePath, bool overwrite = true) {
+ Assert.NotNull(Uiapp);
+ Document doc = null;
+
+ try {
+ if (overwrite && File.Exists(filePath))
+ File.Delete(filePath);
+ }
+ catch { }
+
+ //OpenAndActivateDocument only works if run from the current context
+ UiContext.Send(x => {
+ //if already open, just use it
+ if (!File.Exists(filePath)) {
+ doc = Uiapp.Application.NewProjectDocument(templatePath);
+ doc.SaveAs(filePath);
+ doc.Close();
+ }
+
+ doc = Uiapp.OpenAndActivateDocument(filePath).Document;
+ }
+ , null);
+ Assert.NotNull(doc);
+ return doc;
+ }
+
+ ///
+ /// Runs an Action in a Revit transaction, uses TaskCompletionSource to communicate when done
+ ///
+ /// Action to run
+ /// Revit Document
+ /// Transaction Name
+ /// Enable to swallow all warnings generated by the transaction and prevent them from being raised within Revit
+ ///
+ public static Task RunInTransaction(Action action, Document doc, string transactionName = "transaction", bool ignoreWarnings = false) {
+ var tcs = new TaskCompletionSource();
+ Queue.Add(new Action(() => {
+ try {
+ using (Transaction transaction = new Transaction(doc, transactionName)) {
+ transaction.Start();
+
+ if (ignoreWarnings) {
+ var options = transaction.GetFailureHandlingOptions();
+ options.SetFailuresPreprocessor(new IgnoreAllWarnings());
+ transaction.SetFailureHandlingOptions(options);
+ }
+
+ action.Invoke();
+ transaction.Commit();
+ }
+ }
+ catch (Exception e) {
+ tcs.TrySetException(e);
+ }
+ tcs.TrySetResult("");
+ }));
+
+ EventHandler.Raise();
+
+ return tcs.Task;
+ }
+
+ ///
+ /// Runs an Action, uses TaskCompletionSource to communicate when done
+ ///
+ /// Action to run
+ /// Revit Document
+ ///
+ public static Task Run(Action action, Document doc) {
+ var tcs = new TaskCompletionSource();
+ Queue.Add(new Action(() => {
+ try {
+ action.Invoke();
+ }
+ catch (Exception e) {
+ tcs.TrySetException(e);
+ }
+ tcs.TrySetResult("");
+ }));
+
+ EventHandler.Raise();
+
+ return tcs.Task;
+ }
+
+ ///
+ /// A failures preprocesser that clears any failures that occur within a transaction
+ ///
+ internal class IgnoreAllWarnings : IFailuresPreprocessor {
+ public FailureProcessingResult PreprocessFailures(FailuresAccessor failuresAccessor) {
+ var failList = failuresAccessor.GetFailureMessages();
+
+ foreach (FailureMessageAccessor failure in failList) {
+ failuresAccessor.DeleteWarning(failure);
+ }
+
+ return FailureProcessingResult.Continue;
+ }
+ }
+ #endregion
+ }
+}