|
1 | | -using System.Threading.Tasks; |
| 1 | +using System; |
| 2 | +using System.Collections.Generic; |
| 3 | +using System.Linq; |
| 4 | +using System.Threading.Tasks; |
2 | 5 | using Microsoft.UI; |
3 | 6 | using Microsoft.UI.Xaml; |
4 | 7 | using Microsoft.UI.Xaml.Controls; |
| 8 | +using Microsoft.UI.Xaml.Data; |
| 9 | +using Microsoft.UI.Xaml.Documents; |
5 | 10 | using Microsoft.UI.Xaml.Media; |
6 | 11 | using Uno.UI.Extensions; |
7 | 12 | using Uno.UI.RuntimeTests.Helpers; |
@@ -65,4 +70,165 @@ public async Task When_SeveredSubtree_ContainsDataContextSource() |
65 | 70 | Assert.AreEqual(DC, nested3.DataContext, "3. when reattached, DC (nested3) should still be inherited&unaffected"); |
66 | 71 | Assert.AreEqual(DC, nested4.DataContext, "3. when reattached, DC (nested4) should still be inherited&unaffected"); |
67 | 72 | } |
| 73 | + |
| 74 | +#if HAS_UNO // there is no DC on non-FE DO for winui, not directly* |
| 75 | + [TestMethod] |
| 76 | + [RunsOnUIThread] |
| 77 | + [PlatformCondition(ConditionMode.Include, RuntimeTestPlatforms.Skia)] |
| 78 | + public async Task SingleParentNonFE_Direct_DataContext_Propagation_Works() |
| 79 | + { |
| 80 | + var dc = new { Data = "Context" }; |
| 81 | + |
| 82 | + var run = new Run(); |
| 83 | + run.SetBinding(Run.TextProperty, new Binding { Path = new(nameof(dc.Data)) }); |
| 84 | + var tblock = new TextBlock(); |
| 85 | + tblock.Inlines.Add(run); |
| 86 | + tblock.DataContext = dc; |
| 87 | + |
| 88 | + await UITestHelper.Load(tblock, x => x.IsLoaded); |
| 89 | + |
| 90 | + Assert.AreEqual(dc, run.DataContext); |
| 91 | + Assert.AreEqual(dc.Data, run.Text); |
| 92 | + } |
| 93 | + |
| 94 | + [TestMethod] |
| 95 | + [RunsOnUIThread] |
| 96 | + [PlatformCondition(ConditionMode.Include, RuntimeTestPlatforms.Skia)] |
| 97 | + public async Task MultiParentNonFE_Direct_DataContext_Propagation_WorksOnlyOnce1() |
| 98 | + { |
| 99 | + var brush = new SolidColorBrush(Colors.SkyBlue); |
| 100 | + |
| 101 | +#if DEBUG |
| 102 | + using var disp = brush.RegisterDisposablePropertyChangedCallback( |
| 103 | + SolidColorBrush.DataContextProperty, |
| 104 | + (s, e) => { /* breakpoint here to investigate */ }); |
| 105 | +#endif |
| 106 | + |
| 107 | + // variant: assignment order: foreground > dc |
| 108 | + |
| 109 | + var setup0 = new Control(); |
| 110 | + setup0.Foreground = brush; |
| 111 | + setup0.DataContext = new { Data = "Context 0" }; |
| 112 | + Assert.IsNotNull(brush.DataContext, "0. until it is attached to multiple \"parent\", dc propagate should work"); |
| 113 | + |
| 114 | + var setup1 = new Control(); |
| 115 | + setup1.Foreground = brush; |
| 116 | + setup1.DataContext = new { Data = "Context 1" }; |
| 117 | + Assert.IsNull(brush.DataContext, "1. once it is attached to multiple \"parent\", dc should no longer propagate"); |
| 118 | + |
| 119 | + setup0.Foreground = null; |
| 120 | + setup1.Foreground = null; |
| 121 | + var setup2 = new Control(); |
| 122 | + setup2.Foreground = brush; |
| 123 | + setup2.DataContext = new { Data = "Context 2" }; |
| 124 | + Assert.IsNull(brush.DataContext, "2. once it has been attached to multiple \"parent\", dc shouldn't propagate anymore even if we only have a single parent now"); |
| 125 | + } |
| 126 | + |
| 127 | + [TestMethod] |
| 128 | + [RunsOnUIThread] |
| 129 | + [PlatformCondition(ConditionMode.Include, RuntimeTestPlatforms.Skia)] |
| 130 | + public async Task MultiParentNonFE_Direct_DataContext_Propagation_WorksOnlyOnce2() |
| 131 | + { |
| 132 | + var brush = new SolidColorBrush(Colors.SkyBlue); |
| 133 | + |
| 134 | +#if DEBUG |
| 135 | + using var disp = brush.RegisterDisposablePropertyChangedCallback( |
| 136 | + SolidColorBrush.DataContextProperty, |
| 137 | + (s, e) => { /* breakpoint here to investigate */ }); |
| 138 | +#endif |
| 139 | + |
| 140 | + // variant: assignment order: dc > foreground |
| 141 | + |
| 142 | + var setup0 = new Control(); |
| 143 | + setup0.DataContext = new { Data = "Context 0" }; |
| 144 | + setup0.Foreground = brush; |
| 145 | + Assert.IsNotNull(brush.DataContext, "0. until it is attached to multiple \"parent\", dc propagate should work"); |
| 146 | + |
| 147 | + var setup1 = new Control(); |
| 148 | + setup1.DataContext = new { Data = "Context 1" }; |
| 149 | + setup1.Foreground = brush; |
| 150 | + Assert.IsNull(brush.DataContext, "1. once it is attached to multiple \"parent\", dc should no longer propagate"); |
| 151 | + |
| 152 | + setup0.Foreground = null; |
| 153 | + setup1.Foreground = null; |
| 154 | + var setup2 = new Control(); |
| 155 | + setup2.DataContext = new { Data = "Context 2" }; |
| 156 | + setup2.Foreground = brush; |
| 157 | + Assert.IsNull(brush.DataContext, "2. once it has been attached to multiple \"parent\", dc shouldn't propagate anymore even if we only have a single parent now"); |
| 158 | + } |
| 159 | + |
| 160 | + [TestMethod] |
| 161 | + [RunsOnUIThread] |
| 162 | + [PlatformCondition(ConditionMode.Include, RuntimeTestPlatforms.Skia)] |
| 163 | + public async Task MultiParentNonFE_Inherited_DataContext_Propagation_WorksOnlyOnce() |
| 164 | + { |
| 165 | + // all permutations just in case |
| 166 | + var variants = """ |
| 167 | + A. child.fg > host.dc > host.child |
| 168 | + B. child.fg > host.child > host.dc |
| 169 | + C. host.dc > child.fg > host.child |
| 170 | + D. host.dc > host.child > child.fg |
| 171 | + E. host.child > host.dc > child.fg |
| 172 | + F. host.child > child.fg > host.dc |
| 173 | + """.Split('\n', StringSplitOptions.TrimEntries | StringSplitOptions.RemoveEmptyEntries) |
| 174 | + .Where(x => !x.StartsWith("//")) |
| 175 | + .Select(x => new |
| 176 | + { |
| 177 | + Label = x[0..1], |
| 178 | + Instructions = x[3..].Split(" > "), |
| 179 | + }) |
| 180 | + .ToArray(); |
| 181 | + var instructionMap = new Dictionary<string, Action<Border, Control, object, Brush>> |
| 182 | + { |
| 183 | + ["child.fg"] = (host, child, dc, brush) => child.Foreground = brush, |
| 184 | + ["host.dc"] = (host, child, dc, brush) => host.DataContext = dc, |
| 185 | + ["host.child"] = (host, child, dc, brush) => host.Child = child, |
| 186 | + }; |
| 187 | + |
| 188 | + foreach (var variant in variants) |
| 189 | + { |
| 190 | + var brush = new SolidColorBrush(Colors.SkyBlue); |
| 191 | +#if DEBUG |
| 192 | + using var disp = brush.RegisterDisposablePropertyChangedCallback( |
| 193 | + SolidColorBrush.DataContextProperty, |
| 194 | + (s, e) => { /* breakpoint here to investigate */ }); |
| 195 | +#endif |
| 196 | + |
| 197 | + var setup0 = new |
| 198 | + { |
| 199 | + Host = new Border(), |
| 200 | + Child = new Control(), |
| 201 | + DC = new { Data = $"Context {variant.Label}0" }, |
| 202 | + }; |
| 203 | + instructionMap[variant.Instructions[0]](setup0.Host, setup0.Child, setup0.DC, brush); |
| 204 | + instructionMap[variant.Instructions[1]](setup0.Host, setup0.Child, setup0.DC, brush); |
| 205 | + instructionMap[variant.Instructions[2]](setup0.Host, setup0.Child, setup0.DC, brush); |
| 206 | + Assert.IsNotNull(brush.DataContext, $"{variant.Label}0. until it is attached to multiple \"parent\", dc propagate should work"); |
| 207 | + |
| 208 | + var setup1 = new |
| 209 | + { |
| 210 | + Host = new Border(), |
| 211 | + Child = new Control(), |
| 212 | + DC = new { Data = $"Context {variant.Label}1" }, |
| 213 | + }; |
| 214 | + instructionMap[variant.Instructions[0]](setup1.Host, setup1.Child, setup1.DC, brush); |
| 215 | + instructionMap[variant.Instructions[1]](setup1.Host, setup1.Child, setup1.DC, brush); |
| 216 | + instructionMap[variant.Instructions[2]](setup1.Host, setup1.Child, setup1.DC, brush); |
| 217 | + Assert.IsNull(brush.DataContext, $"{variant.Label}1. once it is attached to multiple \"parent\", dc should no longer propagate"); |
| 218 | + |
| 219 | + setup0.Child.Foreground = null; |
| 220 | + setup1.Child.Foreground = null; |
| 221 | + var setup2 = new |
| 222 | + { |
| 223 | + Host = new Border(), |
| 224 | + Child = new Control(), |
| 225 | + DC = new { Data = $"Context {variant.Label}2" }, |
| 226 | + }; |
| 227 | + instructionMap[variant.Instructions[0]](setup2.Host, setup2.Child, setup2.DC, brush); |
| 228 | + instructionMap[variant.Instructions[1]](setup2.Host, setup2.Child, setup2.DC, brush); |
| 229 | + instructionMap[variant.Instructions[2]](setup2.Host, setup2.Child, setup2.DC, brush); |
| 230 | + Assert.IsNull(brush.DataContext, $"{variant.Label}2. once it has been attached to multiple \"parent\", dc shouldn't propagate anymore even if we only have a single parent now"); |
| 231 | + } |
| 232 | + } |
| 233 | +#endif |
68 | 234 | } |
0 commit comments