├── .gitignore
├── LICENSE
├── README.md
└── src
├── Rvt.Background.sln
└── Rvt.Background
├── ApiContext.cs
├── BackgroundForm.cs
├── BackgroundProcessor.cs
├── BackgroundProcessorCommand.cs
└── Rvt.Background.csproj
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
399 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2024 Ara 3D
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Revit Background Processor
2 |
3 | Perform computations in the background without blocking the Revit UI.
4 |
5 | https://github.com/user-attachments/assets/4e41f514-31ef-4b3d-a33e-1a63f4e9f85b
6 |
7 | # About
8 |
9 | This code contains a library for executing code in the background of Revit with
10 | blocking the UI.
11 |
12 | It uses a queue to contain work items and uses the Revit [UIApplication.Idling](https://www.revitapidocs.com/2019/e233027b-ba8c-0bd1-37b7-93a066efa5a3.htm)
13 | event to process items from the queue, within an alotted time slot.
14 |
15 | This addresses the issue that Revit is single-threaded.
16 |
17 | # Next Steps
18 |
19 | There challenges remain:
20 | 1. the frequency of idle events is inconsistent
21 | 2. do not happen if Revit is a background state.
22 | 3. When "idle" message is too frequent the CPU resources may get hogged
23 |
24 | Jeremy Tammik describes the issue here, and suggests using an External event:
25 | https://thebuildingcoder.typepad.com/blog/2013/12/replacing-an-idling-event-handler-by-an-external-event.html
26 |
27 | This could be added as an option to the current library: by creating an external event and a thread that triggers work periodically.
28 |
29 | However two outstanding problems with that approach are:
30 |
31 | 1. Revit does not actually call the external event Execute method until a cursor movement or some other system event wakes it up.
32 | 2. External events won't fire if Revit doesn't have focus.
33 |
34 | The beginnings of a solution are decribed here: https://adndevblog.typepad.com/aec/2013/07/tricks-to-force-trigger-idling-event.html, but note
35 | that the code there does not actually work.
36 |
37 | Some options to explore are the following, which execute either on a separate thread or process,:
38 |
39 | 1. explicitly moving the mouse a tiny bit
40 | 2. posting the windows message for a mouse move event to the main Revit window
41 |
42 | The final solution may involve chained idle events, along with an external event that checks for changes less frequently
43 |
44 | More empirical data needs to be gathered.
45 |
46 | # Difference from Revit.Async
47 |
48 | [Revit.Async](https://github.com/KennanChan/Revit.Async) solves the problem of assuring that code
49 | is executed within a valid Revit context. This is achieved to a lesser degree by the `ApiContext`
50 | class provided here, or by executing code during an `Idling` event.
51 |
52 | # About the Code
53 |
54 | This code is not a standalone plug-in, the `BackgroundProcessor.cs` and `ApiContext.cs`
55 | files are intended to be reused in your other projects. The `BackgroundForm.cs` Windows Form can
56 | be used for debugging purposes.
57 |
58 | The development version of this code can be found in the
59 | [Bowerbird repository](https://github.com/ara3d/bowerbird/blob/main/Ara3D.Bowerbird.RevitSamples/BackgroundProcessor.cs)
60 |
61 | # Feedback and Contributions
62 |
63 | We warmly welcome contributions and feedback.
64 | We would appreciate learning about any usage of this project.
65 |
66 | # Acknowledgement
67 |
68 | This work is sponsored by HOK.
69 | Thank you to Jeremey Tammik for valuable feedback.
70 | Special thanks to Greg Schleusner for starting and organizing the project.
71 |
72 |
73 |
74 |
75 |
76 |
--------------------------------------------------------------------------------
/src/Rvt.Background.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.8.34525.116
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Rvt.Background", "Rvt.Background\Rvt.Background.csproj", "{0A310011-50E5-4FEE-9934-C2B54B753549}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution items", "solution items", "{6D6731BB-E20B-43A6-9F1F-DE3249981284}"
9 | ProjectSection(SolutionItems) = preProject
10 | ..\LICENSE = ..\LICENSE
11 | ..\README.md = ..\README.md
12 | EndProjectSection
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {0A310011-50E5-4FEE-9934-C2B54B753549}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {0A310011-50E5-4FEE-9934-C2B54B753549}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {0A310011-50E5-4FEE-9934-C2B54B753549}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {0A310011-50E5-4FEE-9934-C2B54B753549}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {152145D8-2835-4B23-A408-8FAE47B018D8}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/src/Rvt.Background/ApiContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Autodesk.Revit.UI;
3 |
4 | namespace Rvt.Background
5 | {
6 | ///
7 | /// This allows you to execute arbitrary Revit code within a valid UI context.
8 | ///
9 | public static class ApiContext
10 | {
11 | public class ExternalEventHandler : IExternalEventHandler
12 | {
13 | public readonly Action Action;
14 | public readonly string Name;
15 |
16 | public ExternalEventHandler(Action action, string name)
17 | {
18 | Action = action ?? throw new ArgumentNullException(nameof(action));
19 | Name = name;
20 | }
21 |
22 | public void Execute(UIApplication app)
23 | => Action(app);
24 |
25 | public string GetName()
26 | => Name;
27 | }
28 |
29 | public static ExternalEvent CreateEvent(Action action, string name)
30 | {
31 | var eeh = new ExternalEventHandler(action, name);
32 | return ExternalEvent.Create(eeh);
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/src/Rvt.Background/BackgroundForm.cs:
--------------------------------------------------------------------------------
1 | namespace Rvt.Background
2 | {
3 | ///
4 | /// This form was designed using Windows designer, and then copied here manually
5 | /// so that it could be used from Bowerbird
6 | ///
7 | public class BackgroundForm : System.Windows.Forms.Form
8 | {
9 | public BackgroundForm()
10 | {
11 | InitializeComponent();
12 | }
13 |
14 | ///
15 | /// Required designer variable.
16 | ///
17 | private System.ComponentModel.IContainer components = null;
18 |
19 | ///
20 | /// Clean up any resources being used.
21 | ///
22 | /// true if managed resources should be disposed; otherwise, false.
23 | protected override void Dispose(bool disposing)
24 | {
25 | if (disposing && (components != null))
26 | {
27 | components.Dispose();
28 | }
29 |
30 | base.Dispose(disposing);
31 | }
32 |
33 | ///
34 | /// Required method for Designer support - do not modify
35 | /// the contents of this method with the code editor.
36 | ///
37 | private void InitializeComponent()
38 | {
39 | this.checkBoxIdleEventNoDelay = new System.Windows.Forms.CheckBox();
40 | this.checkBoxPaused = new System.Windows.Forms.CheckBox();
41 | this.numericUpDownMsecPerBatch = new System.Windows.Forms.NumericUpDown();
42 | this.label1 = new System.Windows.Forms.Label();
43 | this.buttonResetStats = new System.Windows.Forms.Button();
44 | this.checkBoxProcessDuringIdle = new System.Windows.Forms.CheckBox();
45 | this.checkBoxProcessDuringProgress = new System.Windows.Forms.CheckBox();
46 | this.checkBoxEnabled = new System.Windows.Forms.CheckBox();
47 | this.groupBox1 = new System.Windows.Forms.GroupBox();
48 | this.label5 = new System.Windows.Forms.Label();
49 | this.textBoxWorkItemProcessed = new System.Windows.Forms.TextBox();
50 | this.label4 = new System.Windows.Forms.Label();
51 | this.textBoxCpuTimeOnWork = new System.Windows.Forms.TextBox();
52 | this.groupBox2 = new System.Windows.Forms.GroupBox();
53 | this.groupBox3 = new System.Windows.Forms.GroupBox();
54 | this.buttonProcessSome = new System.Windows.Forms.Button();
55 | this.buttonProcessAll = new System.Windows.Forms.Button();
56 | this.label3 = new System.Windows.Forms.Label();
57 | this.textBoxItemsQueued = new System.Windows.Forms.TextBox();
58 | this.buttonClearWork = new System.Windows.Forms.Button();
59 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownMsecPerBatch)).BeginInit();
60 | this.groupBox1.SuspendLayout();
61 | this.groupBox2.SuspendLayout();
62 | this.groupBox3.SuspendLayout();
63 | this.SuspendLayout();
64 | //
65 | // checkBoxIdleEventNoDelay
66 | //
67 | this.checkBoxIdleEventNoDelay.AutoSize = true;
68 | this.checkBoxIdleEventNoDelay.Location = new System.Drawing.Point(6, 91);
69 | this.checkBoxIdleEventNoDelay.Name = "checkBoxIdleEventNoDelay";
70 | this.checkBoxIdleEventNoDelay.Size = new System.Drawing.Size(149, 17);
71 | this.checkBoxIdleEventNoDelay.TabIndex = 0;
72 | this.checkBoxIdleEventNoDelay.Text = "Idling Event without Delay";
73 | this.checkBoxIdleEventNoDelay.UseVisualStyleBackColor = true;
74 | //
75 | // checkBoxPaused
76 | //
77 | this.checkBoxPaused.AutoSize = true;
78 | this.checkBoxPaused.Location = new System.Drawing.Point(18, 76);
79 | this.checkBoxPaused.Name = "checkBoxPaused";
80 | this.checkBoxPaused.Size = new System.Drawing.Size(62, 17);
81 | this.checkBoxPaused.TabIndex = 1;
82 | this.checkBoxPaused.Text = "Paused";
83 | this.checkBoxPaused.UseVisualStyleBackColor = true;
84 | //
85 | // numericUpDownMsecPerBatch
86 | //
87 | this.numericUpDownMsecPerBatch.Location = new System.Drawing.Point(6, 19);
88 | this.numericUpDownMsecPerBatch.Maximum = new decimal(new int[]
89 | {
90 | 5000,
91 | 0,
92 | 0,
93 | 0
94 | });
95 | this.numericUpDownMsecPerBatch.Minimum = new decimal(new int[]
96 | {
97 | 5,
98 | 0,
99 | 0,
100 | 0
101 | });
102 | this.numericUpDownMsecPerBatch.Name = "numericUpDownMsecPerBatch";
103 | this.numericUpDownMsecPerBatch.Size = new System.Drawing.Size(67, 20);
104 | this.numericUpDownMsecPerBatch.TabIndex = 2;
105 | this.numericUpDownMsecPerBatch.Value = new decimal(new int[]
106 | {
107 | 5,
108 | 0,
109 | 0,
110 | 0
111 | });
112 | //
113 | // label1
114 | //
115 | this.label1.AutoSize = true;
116 | this.label1.Location = new System.Drawing.Point(79, 26);
117 | this.label1.Name = "label1";
118 | this.label1.Size = new System.Drawing.Size(111, 13);
119 | this.label1.TabIndex = 3;
120 | this.label1.Text = "Msec per Work Batch";
121 | //
122 | // buttonResetStats
123 | //
124 | this.buttonResetStats.Anchor =
125 | ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top |
126 | System.Windows.Forms.AnchorStyles.Left)
127 | | System.Windows.Forms.AnchorStyles.Right)));
128 | this.buttonResetStats.Location = new System.Drawing.Point(7, 80);
129 | this.buttonResetStats.Name = "buttonResetStats";
130 | this.buttonResetStats.Size = new System.Drawing.Size(238, 23);
131 | this.buttonResetStats.TabIndex = 4;
132 | this.buttonResetStats.Text = "Reset Stats";
133 | this.buttonResetStats.UseVisualStyleBackColor = true;
134 | //
135 | // checkBoxProcessDuringIdle
136 | //
137 | this.checkBoxProcessDuringIdle.AutoSize = true;
138 | this.checkBoxProcessDuringIdle.Location = new System.Drawing.Point(6, 45);
139 | this.checkBoxProcessDuringIdle.Name = "checkBoxProcessDuringIdle";
140 | this.checkBoxProcessDuringIdle.Size = new System.Drawing.Size(116, 17);
141 | this.checkBoxProcessDuringIdle.TabIndex = 15;
142 | this.checkBoxProcessDuringIdle.Text = "Process during Idle";
143 | this.checkBoxProcessDuringIdle.UseVisualStyleBackColor = true;
144 | //
145 | // checkBoxProcessDuringProgress
146 | //
147 | this.checkBoxProcessDuringProgress.AutoSize = true;
148 | this.checkBoxProcessDuringProgress.Location = new System.Drawing.Point(6, 68);
149 | this.checkBoxProcessDuringProgress.Name = "checkBoxProcessDuringProgress";
150 | this.checkBoxProcessDuringProgress.Size = new System.Drawing.Size(140, 17);
151 | this.checkBoxProcessDuringProgress.TabIndex = 16;
152 | this.checkBoxProcessDuringProgress.Text = "Process during Progress";
153 | this.checkBoxProcessDuringProgress.UseVisualStyleBackColor = true;
154 | //
155 | // checkBoxEnabled
156 | //
157 | this.checkBoxEnabled.AutoSize = true;
158 | this.checkBoxEnabled.Checked = true;
159 | this.checkBoxEnabled.CheckState = System.Windows.Forms.CheckState.Checked;
160 | this.checkBoxEnabled.Location = new System.Drawing.Point(13, 12);
161 | this.checkBoxEnabled.Name = "checkBoxEnabled";
162 | this.checkBoxEnabled.Size = new System.Drawing.Size(65, 17);
163 | this.checkBoxEnabled.TabIndex = 17;
164 | this.checkBoxEnabled.Text = "Enabled";
165 | this.checkBoxEnabled.UseVisualStyleBackColor = true;
166 | //
167 | // groupBox1
168 | //
169 | this.groupBox1.Anchor =
170 | ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top |
171 | System.Windows.Forms.AnchorStyles.Left)
172 | | System.Windows.Forms.AnchorStyles.Right)));
173 | this.groupBox1.Controls.Add(this.label5);
174 | this.groupBox1.Controls.Add(this.textBoxWorkItemProcessed);
175 | this.groupBox1.Controls.Add(this.label4);
176 | this.groupBox1.Controls.Add(this.textBoxCpuTimeOnWork);
177 | this.groupBox1.Controls.Add(this.buttonResetStats);
178 | this.groupBox1.Location = new System.Drawing.Point(13, 324);
179 | this.groupBox1.Name = "groupBox1";
180 | this.groupBox1.Size = new System.Drawing.Size(251, 122);
181 | this.groupBox1.TabIndex = 18;
182 | this.groupBox1.TabStop = false;
183 | this.groupBox1.Text = "Statistics";
184 | //
185 | // label5
186 | //
187 | this.label5.AutoSize = true;
188 | this.label5.Location = new System.Drawing.Point(80, 60);
189 | this.label5.Name = "label5";
190 | this.label5.Size = new System.Drawing.Size(95, 13);
191 | this.label5.TabIndex = 17;
192 | this.label5.Text = "# Items Processed";
193 | //
194 | // textBoxWorkItemProcessed
195 | //
196 | this.textBoxWorkItemProcessed.Location = new System.Drawing.Point(7, 53);
197 | this.textBoxWorkItemProcessed.Name = "textBoxWorkItemProcessed";
198 | this.textBoxWorkItemProcessed.ReadOnly = true;
199 | this.textBoxWorkItemProcessed.Size = new System.Drawing.Size(66, 20);
200 | this.textBoxWorkItemProcessed.TabIndex = 16;
201 | //
202 | // label4
203 | //
204 | this.label4.AutoSize = true;
205 | this.label4.Location = new System.Drawing.Point(80, 34);
206 | this.label4.Name = "label4";
207 | this.label4.Size = new System.Drawing.Size(102, 13);
208 | this.label4.TabIndex = 15;
209 | this.label4.Text = "CPU Time on Work ";
210 | //
211 | // textBoxCpuTimeOnWork
212 | //
213 | this.textBoxCpuTimeOnWork.Location = new System.Drawing.Point(7, 27);
214 | this.textBoxCpuTimeOnWork.Name = "textBoxCpuTimeOnWork";
215 | this.textBoxCpuTimeOnWork.ReadOnly = true;
216 | this.textBoxCpuTimeOnWork.Size = new System.Drawing.Size(66, 20);
217 | this.textBoxCpuTimeOnWork.TabIndex = 14;
218 | //
219 | // groupBox2
220 | //
221 | this.groupBox2.Anchor =
222 | ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top |
223 | System.Windows.Forms.AnchorStyles.Left)
224 | | System.Windows.Forms.AnchorStyles.Right)));
225 | this.groupBox2.Controls.Add(this.numericUpDownMsecPerBatch);
226 | this.groupBox2.Controls.Add(this.checkBoxProcessDuringIdle);
227 | this.groupBox2.Controls.Add(this.checkBoxProcessDuringProgress);
228 | this.groupBox2.Controls.Add(this.label1);
229 | this.groupBox2.Controls.Add(this.checkBoxIdleEventNoDelay);
230 | this.groupBox2.Location = new System.Drawing.Point(14, 201);
231 | this.groupBox2.Name = "groupBox2";
232 | this.groupBox2.Size = new System.Drawing.Size(250, 117);
233 | this.groupBox2.TabIndex = 19;
234 | this.groupBox2.TabStop = false;
235 | this.groupBox2.Text = "Options";
236 | //
237 | // groupBox3
238 | //
239 | this.groupBox3.Anchor =
240 | ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top |
241 | System.Windows.Forms.AnchorStyles.Left)
242 | | System.Windows.Forms.AnchorStyles.Right)));
243 | this.groupBox3.Controls.Add(this.buttonProcessSome);
244 | this.groupBox3.Controls.Add(this.buttonProcessAll);
245 | this.groupBox3.Controls.Add(this.label3);
246 | this.groupBox3.Controls.Add(this.textBoxItemsQueued);
247 | this.groupBox3.Controls.Add(this.buttonClearWork);
248 | this.groupBox3.Controls.Add(this.checkBoxPaused);
249 | this.groupBox3.Location = new System.Drawing.Point(13, 35);
250 | this.groupBox3.Name = "groupBox3";
251 | this.groupBox3.Size = new System.Drawing.Size(251, 160);
252 | this.groupBox3.TabIndex = 20;
253 | this.groupBox3.TabStop = false;
254 | this.groupBox3.Text = "Work";
255 | //
256 | // buttonProcessSome
257 | //
258 | this.buttonProcessSome.Anchor =
259 | ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top |
260 | System.Windows.Forms.AnchorStyles.Left)
261 | | System.Windows.Forms.AnchorStyles.Right)));
262 | this.buttonProcessSome.Location = new System.Drawing.Point(7, 128);
263 | this.buttonProcessSome.Name = "buttonProcessSome";
264 | this.buttonProcessSome.Size = new System.Drawing.Size(238, 23);
265 | this.buttonProcessSome.TabIndex = 19;
266 | this.buttonProcessSome.Text = "Process Some Work Now";
267 | this.buttonProcessSome.UseVisualStyleBackColor = true;
268 | //
269 | // buttonProcessAll
270 | //
271 | this.buttonProcessAll.Anchor =
272 | ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top |
273 | System.Windows.Forms.AnchorStyles.Left)
274 | | System.Windows.Forms.AnchorStyles.Right)));
275 | this.buttonProcessAll.Location = new System.Drawing.Point(6, 99);
276 | this.buttonProcessAll.Name = "buttonProcessAll";
277 | this.buttonProcessAll.Size = new System.Drawing.Size(239, 23);
278 | this.buttonProcessAll.TabIndex = 18;
279 | this.buttonProcessAll.Text = "Process All Now";
280 | this.buttonProcessAll.UseVisualStyleBackColor = true;
281 | //
282 | // label3
283 | //
284 | this.label3.AutoSize = true;
285 | this.label3.Location = new System.Drawing.Point(80, 28);
286 | this.label3.Name = "label3";
287 | this.label3.Size = new System.Drawing.Size(83, 13);
288 | this.label3.TabIndex = 17;
289 | this.label3.Text = "# Items Queued";
290 | //
291 | // textBoxItemsQueued
292 | //
293 | this.textBoxItemsQueued.Location = new System.Drawing.Point(6, 21);
294 | this.textBoxItemsQueued.Name = "textBoxItemsQueued";
295 | this.textBoxItemsQueued.ReadOnly = true;
296 | this.textBoxItemsQueued.Size = new System.Drawing.Size(66, 20);
297 | this.textBoxItemsQueued.TabIndex = 16;
298 | //
299 | // buttonClearWork
300 | //
301 | this.buttonClearWork.Anchor =
302 | ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top |
303 | System.Windows.Forms.AnchorStyles.Left)
304 | | System.Windows.Forms.AnchorStyles.Right)));
305 | this.buttonClearWork.Location = new System.Drawing.Point(6, 47);
306 | this.buttonClearWork.Name = "buttonClearWork";
307 | this.buttonClearWork.Size = new System.Drawing.Size(239, 23);
308 | this.buttonClearWork.TabIndex = 15;
309 | this.buttonClearWork.Text = "Clear Work";
310 | this.buttonClearWork.UseVisualStyleBackColor = true;
311 | //
312 | // BackgroundProcessingForm
313 | //
314 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
315 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
316 | this.ClientSize = new System.Drawing.Size(277, 456);
317 | this.Controls.Add(this.groupBox3);
318 | this.Controls.Add(this.groupBox2);
319 | this.Controls.Add(this.groupBox1);
320 | this.Controls.Add(this.checkBoxEnabled);
321 | this.Name = "BackgroundProcessingForm";
322 | this.Text = "Background Processor";
323 | ((System.ComponentModel.ISupportInitialize)(this.numericUpDownMsecPerBatch)).EndInit();
324 | this.groupBox1.ResumeLayout(false);
325 | this.groupBox1.PerformLayout();
326 | this.groupBox2.ResumeLayout(false);
327 | this.groupBox2.PerformLayout();
328 | this.groupBox3.ResumeLayout(false);
329 | this.groupBox3.PerformLayout();
330 | this.ResumeLayout(false);
331 | this.PerformLayout();
332 |
333 | }
334 |
335 | public System.Windows.Forms.CheckBox checkBoxIdleEventNoDelay;
336 | public System.Windows.Forms.CheckBox checkBoxPaused;
337 | public System.Windows.Forms.NumericUpDown numericUpDownMsecPerBatch;
338 | public System.Windows.Forms.Label label1;
339 | public System.Windows.Forms.Button buttonResetStats;
340 | public System.Windows.Forms.CheckBox checkBoxProcessDuringIdle;
341 | public System.Windows.Forms.CheckBox checkBoxProcessDuringProgress;
342 | public System.Windows.Forms.CheckBox checkBoxEnabled;
343 | public System.Windows.Forms.GroupBox groupBox1;
344 | public System.Windows.Forms.Label label5;
345 | public System.Windows.Forms.TextBox textBoxWorkItemProcessed;
346 | public System.Windows.Forms.Label label4;
347 | public System.Windows.Forms.TextBox textBoxCpuTimeOnWork;
348 | public System.Windows.Forms.GroupBox groupBox2;
349 | public System.Windows.Forms.GroupBox groupBox3;
350 | public System.Windows.Forms.Button buttonProcessAll;
351 | public System.Windows.Forms.Label label3;
352 | public System.Windows.Forms.TextBox textBoxItemsQueued;
353 | public System.Windows.Forms.Button buttonClearWork;
354 | public System.Windows.Forms.Button buttonProcessSome;
355 | }
356 | }
357 |
--------------------------------------------------------------------------------
/src/Rvt.Background/BackgroundProcessor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using Autodesk.Revit.ApplicationServices;
5 | using Autodesk.Revit.DB.Events;
6 | using Autodesk.Revit.UI;
7 |
8 | namespace Rvt.Background
9 | {
10 | ///
11 | /// The background processor does arbitrary work in the background while Revit is Idle.
12 | /// It contains a queue of work items (of any user defined type) for later processing.
13 | /// Good practice for choosing a work item type is to not use a Revit API type (e.g., use an integer for element ID).
14 | /// Work processing is performed by a delegate / action provided to the constructors.
15 | /// When an OnIdle or DocumentChanged event occurs, work will be extracted out of the queue
16 | /// and executed using the provided action.
17 | /// This will be repeated until the maximum MSec per batch is reached.
18 | /// You can pause processing, execute all items immediately, or do other work.
19 | ///
20 | public class BackgroundProcessor : IDisposable
21 | {
22 | public readonly Queue Queue = new Queue();
23 | public int MaxMSecPerBatch { get; set; } = 100;
24 | public bool ExecuteNextIdleImmediately { get; set; }
25 | public readonly Action Action;
26 | public readonly UIApplication UIApp;
27 | public Application App => UIApp.Application;
28 | public bool PauseProcessing { get; set; }
29 | public event EventHandler ExceptionEvent;
30 | public readonly Stopwatch WorkStopwatch = new Stopwatch();
31 | public int WorkProcessedCount = 0;
32 | private bool _enabled = false;
33 | public bool DoWorkDuringIdle { get; set; } = true;
34 | public bool DoWorkDuringProgress { get; set; } = true;
35 |
36 | public bool Enabled
37 | {
38 | get => _enabled;
39 | set
40 | {
41 |
42 | if (value)
43 | Attach();
44 | else
45 | Detach();
46 | }
47 | }
48 |
49 | public BackgroundProcessor(Action action, UIApplication uiApp)
50 | {
51 | Action = action;
52 | UIApp = uiApp;
53 | Attach();
54 | }
55 |
56 | public void Detach()
57 | {
58 | if (!_enabled)
59 | return;
60 | App.ProgressChanged -= App_ProgressChanged;
61 | UIApp.Idling -= UiApp_Idling;
62 | _enabled = true;
63 | }
64 |
65 | public void Attach()
66 | {
67 | if (_enabled)
68 | return;
69 | App.ProgressChanged += App_ProgressChanged;
70 | UIApp.Idling += UiApp_Idling;
71 | _enabled = true;
72 | }
73 |
74 | private void App_ProgressChanged(object sender, ProgressChangedEventArgs e)
75 | {
76 | if (!DoWorkDuringProgress || PauseProcessing)
77 | return;
78 | ProcessWork();
79 | }
80 |
81 | public void Dispose()
82 | {
83 | ExceptionEvent = null;
84 | Detach();
85 | }
86 |
87 | private void UiApp_Idling(object sender, Autodesk.Revit.UI.Events.IdlingEventArgs e)
88 | {
89 | if (!DoWorkDuringIdle || PauseProcessing)
90 | return;
91 | ProcessWork();
92 | if (ExecuteNextIdleImmediately)
93 | e.SetRaiseWithoutDelay();
94 | }
95 |
96 | ///
97 | /// Note that this can be called outside of the Revit API context.
98 | ///
99 | public void EnqueueWork(IEnumerable items)
100 | {
101 | foreach (var item in items)
102 | Queue.Enqueue(item);
103 | }
104 |
105 | public bool HasWork
106 | => Queue.Count > 0;
107 |
108 | public void ClearWork()
109 | => Queue.Clear();
110 |
111 | public void ResetStats()
112 | {
113 | WorkStopwatch.Reset();
114 | WorkProcessedCount = 0;
115 | }
116 |
117 | public void ProcessWork(bool doAllNow = false)
118 | {
119 | var startedTime = WorkStopwatch.ElapsedMilliseconds;
120 | WorkStopwatch.Start();
121 | try
122 | {
123 | while (HasWork)
124 | {
125 | var item = Queue.Dequeue();
126 | Action(item);
127 | WorkProcessedCount++;
128 |
129 | var elapsedTime = WorkStopwatch.ElapsedMilliseconds - startedTime;
130 | if (elapsedTime > MaxMSecPerBatch && !doAllNow)
131 | break;
132 | }
133 | }
134 | catch (Exception ex)
135 | {
136 | ExceptionEvent?.Invoke(this, ex);
137 | }
138 | finally
139 | {
140 | WorkStopwatch.Stop();
141 | }
142 | }
143 | }
144 | }
--------------------------------------------------------------------------------
/src/Rvt.Background/BackgroundProcessorCommand.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Linq;
4 | using Autodesk.Revit.DB.Events;
5 | using Autodesk.Revit.UI;
6 |
7 | namespace Rvt.Background
8 | {
9 | ///
10 | /// This is a command for use with Bowerbird.
11 | ///
12 | public class BackgroundProcessorCommand
13 | {
14 | public UIApplication App;
15 | public string Name => "Background Processor";
16 | public BackgroundProcessor Processor;
17 | public BackgroundForm Form;
18 | public ExternalEvent EnableProcessorEvent;
19 | public ExternalEvent DisableProcessorEvent;
20 | public ExternalEvent DisposeProcessorEvent;
21 | public ExternalEvent DoSomeWorkEvent;
22 | public ExternalEvent DoAllWorkEvent;
23 |
24 | public void Execute(object arg)
25 | {
26 | App = arg as UIApplication;
27 | Processor = new BackgroundProcessor(Process, App);
28 | Form = new BackgroundForm();
29 | Form.Update();
30 | Form.Show();
31 | Form.FormClosing += Form_FormClosing;
32 | Form.checkBoxProcessDuringIdle.Click += CheckBoxProcessDuringIdle_Click;
33 | Form.checkBoxProcessDuringProgress.Click += CheckBoxProcessDuringProgress_Click;
34 | Form.checkBoxIdleEventNoDelay.Click += CheckBoxIdleEventNoDelay_Click;
35 | Form.checkBoxEnabled.Click += CheckBoxEnabled_Click;
36 | Form.checkBoxPaused.Click += CheckBoxPauseProcessingOnClick;
37 | Form.numericUpDownMsecPerBatch.ValueChanged += NumericUpDownMsecPerBatch_ValueChanged;
38 | Form.buttonClearWork.Click += ButtonClearWork_Click;
39 | Form.buttonResetStats.Click += ButtonResetStats_Click;
40 | Form.buttonProcessAll.Click += ButtonProcessAll_Click;
41 | Form.buttonProcessSome.Click += ButtonProcessSome_Click;
42 | EnableProcessorEvent = ApiContext.CreateEvent(_ => Processor.Enabled = true, "Enable processor");
43 | DisableProcessorEvent = ApiContext.CreateEvent(_ => Processor.Enabled = false, "Disable processor");
44 |
45 | // Very important that we don't forget to disconnect Revit events in Bowerbird, otherwise we have to restart
46 | App.Application.DocumentChanged += ApplicationOnDocumentChanged;
47 |
48 | DisposeProcessorEvent = ApiContext.CreateEvent(_ =>
49 | {
50 | // Cleaning up the Revit event
51 | App.Application.DocumentChanged -= ApplicationOnDocumentChanged;
52 | Processor.Dispose();
53 | Processor = null;
54 | }, "Disposing processor and closing form");
55 |
56 | DoSomeWorkEvent = ApiContext.CreateEvent(_ => Processor.ProcessWork(), "Processing some work");
57 | DoAllWorkEvent = ApiContext.CreateEvent(_ => Processor.ProcessWork(true), "Processing all work");
58 | }
59 |
60 | private void ButtonProcessSome_Click(object sender, EventArgs e)
61 | {
62 | DoSomeWorkEvent.Raise();
63 | }
64 |
65 | private void ButtonProcessAll_Click(object sender, EventArgs e)
66 | {
67 | DoAllWorkEvent.Raise();
68 | }
69 |
70 | private void CheckBoxEnabled_Click(object sender, EventArgs e)
71 | {
72 | if (Form.checkBoxEnabled.Checked)
73 | EnableProcessorEvent.Raise();
74 | else
75 | DisableProcessorEvent.Raise();
76 | }
77 |
78 | private void CheckBoxProcessDuringProgress_Click(object sender, EventArgs e)
79 | {
80 | Processor.DoWorkDuringProgress = Form.checkBoxProcessDuringProgress.Checked;
81 | }
82 |
83 | private void CheckBoxProcessDuringIdle_Click(object sender, EventArgs e)
84 | {
85 | Processor.DoWorkDuringIdle = Form.checkBoxProcessDuringIdle.Checked;
86 | }
87 |
88 | private void Form_FormClosing(object sender, System.Windows.Forms.FormClosingEventArgs e)
89 | {
90 | DisposeProcessorEvent.Raise();
91 | }
92 |
93 | private void ButtonResetStats_Click(object sender, EventArgs e)
94 | {
95 | Processor.ResetStats();
96 | UpdateForm();
97 | }
98 |
99 | private void ButtonClearWork_Click(object sender, EventArgs e)
100 | {
101 | Processor.ClearWork();
102 | UpdateForm();
103 | }
104 |
105 | private void NumericUpDownMsecPerBatch_ValueChanged(object sender, EventArgs e)
106 | {
107 | Processor.MaxMSecPerBatch = (int)Form.numericUpDownMsecPerBatch.Value;
108 | }
109 |
110 | private void CheckBoxPauseProcessingOnClick(object sender, EventArgs e)
111 | {
112 | Processor.PauseProcessing = Form.checkBoxPaused.Checked;
113 | }
114 |
115 | private void CheckBoxIdleEventNoDelay_Click(object sender, EventArgs e)
116 | {
117 | Processor.ExecuteNextIdleImmediately = Form.checkBoxIdleEventNoDelay.Checked;
118 | }
119 |
120 | private void ApplicationOnDocumentChanged(object sender, DocumentChangedEventArgs e)
121 | {
122 | Processor.EnqueueWork(e.GetAddedElementIds().Select(eid => eid.IntegerValue));
123 | Processor.EnqueueWork(e.GetDeletedElementIds().Select(eid => eid.IntegerValue));
124 | Processor.EnqueueWork(e.GetModifiedElementIds().Select(eid => eid.IntegerValue));
125 | UpdateForm();
126 | }
127 |
128 | public void Process(int id)
129 | {
130 | UpdateForm();
131 | }
132 |
133 | public void UpdateForm()
134 | {
135 | Form.textBoxCpuTimeOnWork.Text = (Processor.WorkStopwatch.ElapsedMilliseconds / 1000f).ToString(CultureInfo.InvariantCulture);
136 | Form.textBoxItemsQueued.Text = Processor.Queue.Count.ToString();
137 | Form.textBoxWorkItemProcessed.Text = Processor.WorkProcessedCount.ToString();
138 | Form.checkBoxPaused.Checked = Processor.PauseProcessing;
139 | Form.checkBoxEnabled.Checked = Processor.Enabled;
140 | Form.checkBoxProcessDuringIdle.Checked = Processor.DoWorkDuringIdle;
141 | Form.checkBoxProcessDuringProgress.Checked = Processor.DoWorkDuringProgress;
142 | Form.checkBoxIdleEventNoDelay.Checked = Processor.ExecuteNextIdleImmediately;
143 | Form.numericUpDownMsecPerBatch.Value = Processor.MaxMSecPerBatch;
144 | System.Windows.Forms.Application.DoEvents();
145 | }
146 | }
147 | }
--------------------------------------------------------------------------------
/src/Rvt.Background/Rvt.Background.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net48
4 | true
5 | net48
6 | true
7 |
8 |
9 |
10 |
11 | ..\..\..\ara3d\vendor\Revit\2023\RevitAPI.dll
12 |
13 |
14 | ..\..\..\ara3d\vendor\Revit\2023\RevitAPIUI.dll
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------