diff --git a/src/DynamoCoreWpf/Interfaces/IWatchHandler.cs b/src/DynamoCoreWpf/Interfaces/IWatchHandler.cs index 8c0b6af20dc..901c3704695 100644 --- a/src/DynamoCoreWpf/Interfaces/IWatchHandler.cs +++ b/src/DynamoCoreWpf/Interfaces/IWatchHandler.cs @@ -81,7 +81,9 @@ private WatchViewModel ProcessThing(object value, ProtoCore.RuntimeCore runtimeC foreach (var e in keys.Zip(values, (key, val) => new { key, val })) { - node.Children.Add(ProcessThing(e.val, runtimeCore, tag + ":" + e.key, showRawData, callback)); + var child = ProcessThing(e.val, runtimeCore, tag + ":" + e.key, showRawData, callback); + child.DictionaryKey = e.key; + node.Children.Add(child); } return node; @@ -93,7 +95,9 @@ private WatchViewModel ProcessThing(object value, ProtoCore.RuntimeCore runtimeC foreach (var e in dict.Keys.Zip(dict.Values, (key, val) => new { key, val })) { - node.Children.Add(ProcessThing(e.val, runtimeCore, tag + ":" + e.key, showRawData, callback)); + var child = ProcessThing(e.val, runtimeCore, tag + ":" + e.key, showRawData, callback); + child.DictionaryKey = e.key; + node.Children.Add(child); } return node; @@ -204,7 +208,9 @@ private WatchViewModel ProcessThing(MirrorData data, ProtoCore.RuntimeCore runti foreach (var e in keys.Zip(values, (key, value) => new { key, value })) { - node.Children.Add(ProcessThing(e.value, runtimeCore, tag + ":" + e.key, showRawData, callback)); + var child = ProcessThing(e.value, runtimeCore, tag + ":" + e.key, showRawData, callback); + child.DictionaryKey = e.key; + node.Children.Add(child); } return node; diff --git a/src/DynamoCoreWpf/ViewModels/Preview/WatchViewModel.cs b/src/DynamoCoreWpf/ViewModels/Preview/WatchViewModel.cs index 1e0106e9f2d..b7a933701e1 100644 --- a/src/DynamoCoreWpf/ViewModels/Preview/WatchViewModel.cs +++ b/src/DynamoCoreWpf/ViewModels/Preview/WatchViewModel.cs @@ -48,6 +48,7 @@ internal void Click() private readonly Action tagGeometry; private bool isCollection; private string valueType; + private string dictionaryKey; // Instance variable for the number of items in the list private int numberOfItems; @@ -100,13 +101,18 @@ public string Link } /// - /// Returns the last index of the Path, - /// surrounded with square brackets. + /// Returns the last segment of for display. + /// For list items, the segment is returned as-is; for non-list items, the segment + /// is returned with surrounding spaces. + /// When this item is a dictionary child, returns the dictionary key directly + /// (without splitting on ':') so that keys containing ':' are displayed correctly. /// public string ViewPath { get { + if (dictionaryKey != null) + return string.Format(NodeLabel == LIST ? "{0}" : " {0} ", dictionaryKey); var splits = Path.Split(':'); if (splits.Count() == 1) return string.Empty; @@ -114,6 +120,24 @@ public string ViewPath } } + /// + /// When this item is a direct child of a dictionary, stores the dictionary key + /// so that can return it without splitting on ':'. + /// Setting this property raises a change notification for . + /// + internal string DictionaryKey + { + get => dictionaryKey; + set + { + if (dictionaryKey != value) + { + dictionaryKey = value; + RaisePropertyChanged(nameof(ViewPath)); + } + } + } + /// /// A path describing the location of the data. /// Path takes the form var_xxxx...:0:1:2, where diff --git a/test/DynamoCoreWpf3Tests/WatchNodeTests.cs b/test/DynamoCoreWpf3Tests/WatchNodeTests.cs index b279c7465ab..358f5665114 100644 --- a/test/DynamoCoreWpf3Tests/WatchNodeTests.cs +++ b/test/DynamoCoreWpf3Tests/WatchNodeTests.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Threading; using CoreNodeModels; +using DesignScript.Builtin; using Dynamo.Controls; using Dynamo.Graph.Nodes; using Dynamo.Graph.Nodes.ZeroTouch; @@ -483,7 +484,32 @@ public void WatchNodeWithBadSize() Assert.AreEqual(100, watchNode.Height); } - [Test] + [Test] + public void WatchDictionaryWithColonInKey_ViewPathDisplaysFullKey() + { + // Arrange - dictionary keys containing ':' were previously displayed incorrectly because + // ViewPath split the Path string on ':' and returned only the last segment. + var keys = new[] { "Hope:", ":This Isn't Right:", "help" }; + var values = new object[] { 2, 5, 1 }; + var dict = Dictionary.ByKeysValues(keys, values); + + var watchVM = ViewModel.WatchHandler.GenerateWatchViewModelForData( + dict, + null, + null, + "test_tag", + false); + + // Assert that ViewPath of each child returns the full key, including any ':' characters. + // Use a set-based check to be independent of the dictionary iteration order. + Assert.AreEqual(3, watchVM.Children.Count); + var viewPaths = watchVM.Children.Select(c => c.ViewPath.Trim()).ToList(); + CollectionAssert.Contains(viewPaths, "Hope:"); + CollectionAssert.Contains(viewPaths, ":This Isn't Right:"); + CollectionAssert.Contains(viewPaths, "help"); + } + + [Test] public void GetNodeLabelTree() { // Arrange