InteractiveTests.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using Avalonia.Interactivity;
  5. using Avalonia.VisualTree;
  6. using Xunit;
  7. namespace Avalonia.Base.UnitTests.Interactivity
  8. {
  9. public class InteractiveTests
  10. {
  11. [Fact]
  12. public void Direct_Event_Should_Go_Straight_To_Source()
  13. {
  14. var ev = new RoutedEvent("test", RoutingStrategies.Direct, typeof(RoutedEventArgs), typeof(TestInteractive));
  15. var invoked = new List<string>();
  16. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(((TestInteractive)s).Name);
  17. var target = CreateTree(ev, handler, RoutingStrategies.Direct);
  18. var args = new RoutedEventArgs(ev, target);
  19. target.RaiseEvent(args);
  20. Assert.Equal(new[] { "2b" }, invoked);
  21. }
  22. [Fact]
  23. public void Direct_Event_Should_Have_Route_Set_To_Direct()
  24. {
  25. var ev = new RoutedEvent("test", RoutingStrategies.Direct, typeof(RoutedEventArgs), typeof(TestInteractive));
  26. bool called = false;
  27. EventHandler<RoutedEventArgs> handler = (s, e) =>
  28. {
  29. Assert.Equal(RoutingStrategies.Direct, e.Route);
  30. called = true;
  31. };
  32. var target = CreateTree(ev, handler, RoutingStrategies.Direct);
  33. var args = new RoutedEventArgs(ev, target);
  34. target.RaiseEvent(args);
  35. Assert.True(called);
  36. }
  37. [Fact]
  38. public void Bubbling_Event_Should_Bubble_Up()
  39. {
  40. var ev = new RoutedEvent("test", RoutingStrategies.Bubble, typeof(RoutedEventArgs), typeof(TestInteractive));
  41. var invoked = new List<string>();
  42. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(((TestInteractive)s).Name);
  43. var target = CreateTree(ev, handler, RoutingStrategies.Bubble | RoutingStrategies.Tunnel);
  44. var args = new RoutedEventArgs(ev, target);
  45. target.RaiseEvent(args);
  46. Assert.Equal(new[] { "2b", "1" }, invoked);
  47. }
  48. [Fact]
  49. public void Tunneling_Event_Should_Tunnel()
  50. {
  51. var ev = new RoutedEvent("test", RoutingStrategies.Tunnel, typeof(RoutedEventArgs), typeof(TestInteractive));
  52. var invoked = new List<string>();
  53. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(((TestInteractive)s).Name);
  54. var target = CreateTree(ev, handler, RoutingStrategies.Bubble | RoutingStrategies.Tunnel);
  55. var args = new RoutedEventArgs(ev, target);
  56. target.RaiseEvent(args);
  57. Assert.Equal(new[] { "1", "2b" }, invoked);
  58. }
  59. [Fact]
  60. public void Tunneling_Bubbling_Event_Should_Tunnel_Then_Bubble_Up()
  61. {
  62. var ev = new RoutedEvent(
  63. "test",
  64. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  65. typeof(RoutedEventArgs),
  66. typeof(TestInteractive));
  67. var invoked = new List<string>();
  68. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(((TestInteractive)s).Name);
  69. var target = CreateTree(ev, handler, RoutingStrategies.Bubble | RoutingStrategies.Tunnel);
  70. var args = new RoutedEventArgs(ev, target);
  71. target.RaiseEvent(args);
  72. Assert.Equal(new[] { "1", "2b", "2b", "1" }, invoked);
  73. }
  74. [Fact]
  75. public void Events_Should_Have_Route_Set()
  76. {
  77. var ev = new RoutedEvent(
  78. "test",
  79. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  80. typeof(RoutedEventArgs),
  81. typeof(TestInteractive));
  82. var invoked = new List<RoutingStrategies>();
  83. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(e.Route);
  84. var target = CreateTree(ev, handler, RoutingStrategies.Bubble | RoutingStrategies.Tunnel);
  85. var args = new RoutedEventArgs(ev, target);
  86. target.RaiseEvent(args);
  87. Assert.Equal(new[]
  88. {
  89. RoutingStrategies.Tunnel,
  90. RoutingStrategies.Tunnel,
  91. RoutingStrategies.Bubble,
  92. RoutingStrategies.Bubble,
  93. },
  94. invoked);
  95. }
  96. [Fact]
  97. public void Handled_Bubbled_Event_Should_Not_Propogate_Further()
  98. {
  99. var ev = new RoutedEvent("test", RoutingStrategies.Bubble, typeof(RoutedEventArgs), typeof(TestInteractive));
  100. var invoked = new List<string>();
  101. EventHandler<RoutedEventArgs> handler = (s, e) =>
  102. {
  103. var t = (TestInteractive)s;
  104. invoked.Add(t.Name);
  105. e.Handled = t.Name == "2b";
  106. };
  107. var target = CreateTree(ev, handler, RoutingStrategies.Bubble);
  108. var args = new RoutedEventArgs(ev, target);
  109. target.RaiseEvent(args);
  110. Assert.Equal(new[] { "2b" }, invoked);
  111. }
  112. [Fact]
  113. public void Handled_Tunnelled_Event_Should_Not_Propogate_Further()
  114. {
  115. var ev = new RoutedEvent(
  116. "test",
  117. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  118. typeof(RoutedEventArgs),
  119. typeof(TestInteractive));
  120. var invoked = new List<string>();
  121. EventHandler<RoutedEventArgs> handler = (s, e) =>
  122. {
  123. var t = (TestInteractive)s;
  124. invoked.Add(t.Name);
  125. e.Handled = t.Name == "2b";
  126. };
  127. var target = CreateTree(ev, handler, RoutingStrategies.Bubble | RoutingStrategies.Tunnel);
  128. var args = new RoutedEventArgs(ev, target);
  129. target.RaiseEvent(args);
  130. Assert.Equal(new[] { "1", "2b" }, invoked);
  131. }
  132. [Fact]
  133. public void Direct_Subscription_Should_Not_Catch_Tunneling_Or_Bubbling()
  134. {
  135. var ev = new RoutedEvent(
  136. "test",
  137. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  138. typeof(RoutedEventArgs),
  139. typeof(TestInteractive));
  140. var count = 0;
  141. EventHandler<RoutedEventArgs> handler = (s, e) =>
  142. {
  143. ++count;
  144. };
  145. var target = CreateTree(ev, handler, RoutingStrategies.Direct);
  146. var args = new RoutedEventArgs(ev, target);
  147. target.RaiseEvent(args);
  148. Assert.Equal(0, count);
  149. }
  150. [Fact]
  151. public void Bubbling_Subscription_Should_Not_Catch_Tunneling()
  152. {
  153. var ev = new RoutedEvent(
  154. "test",
  155. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  156. typeof(RoutedEventArgs),
  157. typeof(TestInteractive));
  158. var count = 0;
  159. EventHandler<RoutedEventArgs> handler = (s, e) =>
  160. {
  161. Assert.Equal(RoutingStrategies.Bubble, e.Route);
  162. ++count;
  163. };
  164. var target = CreateTree(ev, handler, RoutingStrategies.Bubble);
  165. var args = new RoutedEventArgs(ev, target);
  166. target.RaiseEvent(args);
  167. Assert.Equal(2, count);
  168. }
  169. [Fact]
  170. public void Tunneling_Subscription_Should_Not_Catch_Bubbling()
  171. {
  172. var ev = new RoutedEvent(
  173. "test",
  174. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  175. typeof(RoutedEventArgs),
  176. typeof(TestInteractive));
  177. var count = 0;
  178. EventHandler<RoutedEventArgs> handler = (s, e) =>
  179. {
  180. Assert.Equal(RoutingStrategies.Tunnel, e.Route);
  181. ++count;
  182. };
  183. var target = CreateTree(ev, handler, RoutingStrategies.Tunnel);
  184. var args = new RoutedEventArgs(ev, target);
  185. target.RaiseEvent(args);
  186. Assert.Equal(2, count);
  187. }
  188. [Fact]
  189. public void Event_Should_Should_Keep_Propogating_To_HandedEventsToo_Handlers()
  190. {
  191. var ev = new RoutedEvent(
  192. "test",
  193. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  194. typeof(RoutedEventArgs),
  195. typeof(TestInteractive));
  196. var invoked = new List<string>();
  197. EventHandler<RoutedEventArgs> handler = (s, e) =>
  198. {
  199. invoked.Add(((TestInteractive)s).Name);
  200. e.Handled = true;
  201. };
  202. var target = CreateTree(ev, handler, RoutingStrategies.Bubble | RoutingStrategies.Tunnel, true);
  203. var args = new RoutedEventArgs(ev, target);
  204. target.RaiseEvent(args);
  205. Assert.Equal(new[] { "1", "2b", "2b", "1" }, invoked);
  206. }
  207. [Fact]
  208. public void Direct_Class_Handlers_Should_Be_Called()
  209. {
  210. var ev = new RoutedEvent(
  211. "test",
  212. RoutingStrategies.Direct,
  213. typeof(RoutedEventArgs),
  214. typeof(TestInteractive));
  215. var invoked = new List<string>();
  216. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(((TestInteractive)s).Name);
  217. var target = CreateTree(ev, null, 0);
  218. ev.AddClassHandler(typeof(TestInteractive), handler, RoutingStrategies.Direct);
  219. var args = new RoutedEventArgs(ev, target);
  220. target.RaiseEvent(args);
  221. Assert.Equal(new[] { "2b" }, invoked);
  222. }
  223. [Fact]
  224. public void Tunneling_Class_Handlers_Should_Be_Called()
  225. {
  226. var ev = new RoutedEvent(
  227. "test",
  228. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  229. typeof(RoutedEventArgs),
  230. typeof(TestInteractive));
  231. var invoked = new List<string>();
  232. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(((TestInteractive)s).Name);
  233. var target = CreateTree(ev, null, 0);
  234. ev.AddClassHandler(typeof(TestInteractive), handler, RoutingStrategies.Tunnel);
  235. var args = new RoutedEventArgs(ev, target);
  236. target.RaiseEvent(args);
  237. Assert.Equal(new[] { "1", "2b" }, invoked);
  238. }
  239. [Fact]
  240. public void Bubbling_Class_Handlers_Should_Be_Called()
  241. {
  242. var ev = new RoutedEvent(
  243. "test",
  244. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  245. typeof(RoutedEventArgs),
  246. typeof(TestInteractive));
  247. var invoked = new List<string>();
  248. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(((TestInteractive)s).Name);
  249. var target = CreateTree(ev, null, 0);
  250. ev.AddClassHandler(typeof(TestInteractive), handler, RoutingStrategies.Bubble);
  251. var args = new RoutedEventArgs(ev, target);
  252. target.RaiseEvent(args);
  253. Assert.Equal(new[] { "2b", "1" }, invoked);
  254. }
  255. [Fact]
  256. public void Typed_Class_Handlers_Should_Be_Called()
  257. {
  258. var ev = new RoutedEvent<RoutedEventArgs>(
  259. "test",
  260. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  261. typeof(TestInteractive));
  262. var target = CreateTree(ev, null, 0);
  263. ev.AddClassHandler<TestInteractive>((x, e) => x.ClassHandler(e), RoutingStrategies.Bubble);
  264. var args = new RoutedEventArgs(ev, target);
  265. target.RaiseEvent(args);
  266. Assert.True(target.ClassHandlerInvoked);
  267. Assert.True(target.GetVisualParent<TestInteractive>().ClassHandlerInvoked);
  268. }
  269. [Fact]
  270. public void Typed_Class_Handlers_Should_Be_Called_For_Handled_Events()
  271. {
  272. var ev = new RoutedEvent<RoutedEventArgs>(
  273. "test",
  274. RoutingStrategies.Bubble | RoutingStrategies.Tunnel,
  275. typeof(TestInteractive));
  276. var target = CreateTree(ev, null, 0);
  277. ev.AddClassHandler<TestInteractive>((x, e) => x.MarkEventAsHandled(e), RoutingStrategies.Bubble);
  278. ev.AddClassHandler<TestInteractive>((x, e) => x.ClassHandler(e), RoutingStrategies.Bubble, handledEventsToo: true);
  279. var args = new RoutedEventArgs(ev, target);
  280. target.RaiseEvent(args);
  281. Assert.True(args.Handled);
  282. Assert.True(target.ClassHandlerInvoked);
  283. Assert.True(target.GetVisualParent<TestInteractive>().ClassHandlerInvoked);
  284. }
  285. [Fact]
  286. public void GetObservable_Should_Listen_To_Event()
  287. {
  288. var ev = new RoutedEvent<RoutedEventArgs>("test", RoutingStrategies.Direct, typeof(TestInteractive));
  289. var target = new TestInteractive();
  290. var called = 0;
  291. var subscription = target.GetObservable(ev).Subscribe(_ => ++called);
  292. var args = new RoutedEventArgs(ev, target);
  293. target.RaiseEvent(args);
  294. subscription.Dispose();
  295. target.RaiseEvent(args);
  296. Assert.Equal(1, called);
  297. }
  298. [Fact]
  299. public void Removing_Control_In_Handler_Should_Not_Stop_Event()
  300. {
  301. // Issue #3176
  302. var ev = new RoutedEvent("test", RoutingStrategies.Bubble, typeof(RoutedEventArgs), typeof(TestInteractive));
  303. var invoked = new List<string>();
  304. EventHandler<RoutedEventArgs> handler = (s, e) => invoked.Add(((TestInteractive)s).Name);
  305. var parent = CreateTree(ev, handler, RoutingStrategies.Bubble | RoutingStrategies.Tunnel);
  306. var target = (Interactive)parent.GetVisualChildren().Single();
  307. EventHandler<RoutedEventArgs> removeHandler = (s, e) =>
  308. {
  309. parent.Children = Array.Empty<Visual>();
  310. };
  311. target.AddHandler(ev, removeHandler);
  312. var args = new RoutedEventArgs(ev, target);
  313. target.RaiseEvent(args);
  314. Assert.Equal(new[] { "3", "2b", "1" }, invoked);
  315. }
  316. private static TestInteractive CreateTree(
  317. RoutedEvent ev,
  318. EventHandler<RoutedEventArgs> handler,
  319. RoutingStrategies handlerRoutes,
  320. bool handledEventsToo = false)
  321. {
  322. TestInteractive target;
  323. var tree = new TestInteractive
  324. {
  325. Name = "1",
  326. Children = new[]
  327. {
  328. new TestInteractive
  329. {
  330. Name = "2a",
  331. },
  332. (target = new TestInteractive
  333. {
  334. Name = "2b",
  335. Children = new[]
  336. {
  337. new TestInteractive
  338. {
  339. Name = "3",
  340. },
  341. },
  342. }),
  343. }
  344. };
  345. if (handler != null)
  346. {
  347. foreach (var i in tree.GetSelfAndVisualDescendants().Cast<Interactive>())
  348. {
  349. i.AddHandler(ev, handler, handlerRoutes, handledEventsToo);
  350. }
  351. }
  352. return target;
  353. }
  354. private class TestInteractive : Interactive
  355. {
  356. public bool ClassHandlerInvoked { get; private set; }
  357. public new string Name { get; set; }
  358. public IEnumerable<Visual> Children
  359. {
  360. get
  361. {
  362. return ((Visual)this).VisualChildren.AsEnumerable();
  363. }
  364. set
  365. {
  366. VisualChildren.Clear();
  367. VisualChildren.AddRange(value.Cast<Visual>());
  368. }
  369. }
  370. public void ClassHandler(RoutedEventArgs e)
  371. {
  372. ClassHandlerInvoked = true;
  373. }
  374. public void MarkEventAsHandled(RoutedEventArgs e)
  375. {
  376. e.Handled = true;
  377. }
  378. }
  379. }
  380. }