|
4 | 4 | using System.IO; |
5 | 5 | using System.Linq; |
6 | 6 | using System.Threading; |
| 7 | +using System.Windows; |
7 | 8 | using System.Windows.Input; |
8 | 9 | using System.Windows.Media; |
9 | 10 | using Dynamo.Controls; |
10 | 11 | using Dynamo.Graph; |
11 | 12 | using Dynamo.Graph.Workspaces; |
12 | 13 | using Dynamo.Models; |
13 | 14 | using Dynamo.Selection; |
| 15 | +using Dynamo.UI.Prompts; |
14 | 16 | using Dynamo.ViewModels; |
15 | 17 | using DynamoCoreWpfTests.Utility; |
16 | 18 | using NUnit.Framework; |
@@ -381,6 +383,95 @@ private void NodeNameTest_PropChangedHandler(object sender, System.ComponentMode |
381 | 383 | var temp = (sender as NodeViewModel).Name; |
382 | 384 | } |
383 | 385 |
|
| 386 | + /// <summary> |
| 387 | + /// Regression test: opening the Package Manager or Preferences window temporarily sets |
| 388 | + /// dynamoViewModel.Owner to that child window. If the child window is closed without |
| 389 | + /// restoring the owner, the EditWindow constructor throws InvalidOperationException |
| 390 | + /// ("Cannot set owner to a Window that has been closed") when a node rename is triggered. |
| 391 | + /// </summary> |
| 392 | + [Test] |
| 393 | + [Category("RegressionTests")] |
| 394 | + public void WhenDynamoViewModelOwnerIsClosedWindowThenEditWindowDoesNotThrow() |
| 395 | + { |
| 396 | + // Arrange: open a graph with at least one node. |
| 397 | + Open(@"UI\CoreUINodes.dyn"); |
| 398 | + DispatcherUtil.DoEvents(); |
| 399 | + |
| 400 | + Window originalOwner = null; |
| 401 | + try |
| 402 | + { |
| 403 | + // Simulate the stale-owner state left by PackageManagerView / PreferencesView: |
| 404 | + // a secondary window sets itself as dynamoViewModel.Owner, then closes |
| 405 | + // without restoring the owner back to the main DynamoView. |
| 406 | + View.Dispatcher.Invoke(() => |
| 407 | + { |
| 408 | + originalOwner = ViewModel.Owner; |
| 409 | + var childWindow = new Window { Owner = View }; |
| 410 | + childWindow.Show(); |
| 411 | + childWindow.Close(); |
| 412 | + // Owner now points to a closed window — the bug condition. |
| 413 | + ViewModel.Owner = childWindow; |
| 414 | + }); |
| 415 | + |
| 416 | + // Act & Assert: constructing EditWindow (what node rename does) must not throw. |
| 417 | + // Before the fix, this raised: |
| 418 | + // System.InvalidOperationException: Cannot set owner to a Window that has been closed. |
| 419 | + Assert.DoesNotThrow(() => |
| 420 | + { |
| 421 | + View.Dispatcher.Invoke(() => |
| 422 | + { |
| 423 | + var editWindow = new EditWindow(ViewModel, false, true); |
| 424 | + editWindow.Close(); |
| 425 | + }); |
| 426 | + }); |
| 427 | + } |
| 428 | + finally |
| 429 | + { |
| 430 | + // Restore owner to avoid leaking stale state into subsequent tests. |
| 431 | + View.Dispatcher.Invoke(() => ViewModel.Owner = originalOwner ?? View); |
| 432 | + } |
| 433 | + } |
| 434 | + |
| 435 | + /// <summary> |
| 436 | + /// Verifies that dynamoViewModel.Owner is restored to the main DynamoView after a |
| 437 | + /// child window that took over ownership is closed via its Closed event — the same |
| 438 | + /// pattern used by HandlePackageManagerWindowClosed and PreferencesView_Closed. |
| 439 | + /// </summary> |
| 440 | + [Test] |
| 441 | + [Category("RegressionTests")] |
| 442 | + public void WhenChildWindowClosesOwnerIsRestoredToDynamoView() |
| 443 | + { |
| 444 | + View.Dispatcher.Invoke(() => |
| 445 | + { |
| 446 | + Assert.AreEqual(View, ViewModel.Owner, |
| 447 | + "Owner should be the main DynamoView after startup."); |
| 448 | + |
| 449 | + // Simulate PackageManagerView / PreferencesView taking ownership. |
| 450 | + var childWindow = new Window { Owner = View }; |
| 451 | + childWindow.Show(); |
| 452 | + ViewModel.Owner = childWindow; |
| 453 | + |
| 454 | + Assert.AreEqual(childWindow, ViewModel.Owner, |
| 455 | + "Owner should be the child window while it is open."); |
| 456 | + |
| 457 | + // Wire up the Closed handler the same way HandlePackageManagerWindowClosed |
| 458 | + // and PreferencesView_Closed do — restore the owner to the parent window. |
| 459 | + childWindow.Closed += (s, e) => ViewModel.Owner = ((Window)s).Owner ?? View; |
| 460 | + |
| 461 | + // Act: close the child window, which fires the Closed handler. |
| 462 | + childWindow.Close(); |
| 463 | + }); |
| 464 | + |
| 465 | + DispatcherUtil.DoEvents(); |
| 466 | + |
| 467 | + // Assert: the Closed handler restored the owner — not manual assignment. |
| 468 | + View.Dispatcher.Invoke(() => |
| 469 | + { |
| 470 | + Assert.AreEqual(View, ViewModel.Owner, |
| 471 | + "Owner must be restored to the main DynamoView after the child window closes."); |
| 472 | + }); |
| 473 | + } |
| 474 | + |
384 | 475 | /// <summary> |
385 | 476 | /// Check if elements are correctly displayed/collapsed on zoom level change |
386 | 477 | /// Current zoom level is 0.4 (hard-coded in multiple Converters |
|
0 commit comments