SelectingItemsControlTests.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. // Copyright (c) The Perspex Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System.Collections.ObjectModel;
  4. using Perspex.Collections;
  5. using Perspex.Controls.Presenters;
  6. using Perspex.Controls.Primitives;
  7. using Perspex.Controls.Templates;
  8. using Perspex.Input;
  9. using Perspex.Interactivity;
  10. using Xunit;
  11. namespace Perspex.Controls.UnitTests.Primitives
  12. {
  13. public class SelectingItemsControlTests
  14. {
  15. [Fact]
  16. public void SelectedIndex_Should_Initially_Be_Minus_1()
  17. {
  18. var items = new[]
  19. {
  20. new Item(),
  21. new Item(),
  22. };
  23. var target = new SelectingItemsControl
  24. {
  25. Items = items,
  26. Template = Template(),
  27. };
  28. Assert.Equal(-1, target.SelectedIndex);
  29. }
  30. [Fact]
  31. public void Item_IsSelected_Should_Initially_Be_False()
  32. {
  33. var items = new[]
  34. {
  35. new Item(),
  36. new Item(),
  37. };
  38. var target = new SelectingItemsControl
  39. {
  40. Items = items,
  41. Template = Template(),
  42. };
  43. target.ApplyTemplate();
  44. Assert.False(items[0].IsSelected);
  45. Assert.False(items[1].IsSelected);
  46. }
  47. [Fact]
  48. public void Setting_SelectedItem_Should_Set_Item_IsSelected_True()
  49. {
  50. var items = new[]
  51. {
  52. new Item(),
  53. new Item(),
  54. };
  55. var target = new SelectingItemsControl
  56. {
  57. Items = items,
  58. Template = Template(),
  59. };
  60. target.ApplyTemplate();
  61. target.SelectedItem = items[1];
  62. Assert.False(items[0].IsSelected);
  63. Assert.True(items[1].IsSelected);
  64. }
  65. [Fact]
  66. public void Setting_SelectedItem_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
  67. {
  68. var items = new[]
  69. {
  70. new Item(),
  71. new Item(),
  72. };
  73. var target = new SelectingItemsControl
  74. {
  75. Items = items,
  76. Template = Template(),
  77. };
  78. target.SelectedItem = items[1];
  79. target.ApplyTemplate();
  80. Assert.False(items[0].IsSelected);
  81. Assert.True(items[1].IsSelected);
  82. }
  83. [Fact]
  84. public void Setting_SelectedIndex_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
  85. {
  86. var items = new[]
  87. {
  88. new Item(),
  89. new Item(),
  90. };
  91. var target = new SelectingItemsControl
  92. {
  93. Items = items,
  94. Template = Template(),
  95. };
  96. target.SelectedIndex = 1;
  97. target.ApplyTemplate();
  98. Assert.False(items[0].IsSelected);
  99. Assert.True(items[1].IsSelected);
  100. }
  101. [Fact]
  102. public void Setting_SelectedItem_Should_Set_SelectedIndex()
  103. {
  104. var items = new[]
  105. {
  106. new Item(),
  107. new Item(),
  108. };
  109. var target = new SelectingItemsControl
  110. {
  111. Items = items,
  112. Template = Template(),
  113. };
  114. target.ApplyTemplate();
  115. target.SelectedItem = items[1];
  116. Assert.Equal(items[1], target.SelectedItem);
  117. Assert.Equal(1, target.SelectedIndex);
  118. }
  119. [Fact]
  120. public void Setting_SelectedItem_To_Not_Present_Item_Should_Clear_Selection()
  121. {
  122. var items = new[]
  123. {
  124. new Item(),
  125. new Item(),
  126. };
  127. var target = new SelectingItemsControl
  128. {
  129. Items = items,
  130. Template = Template(),
  131. };
  132. target.ApplyTemplate();
  133. target.SelectedItem = items[1];
  134. Assert.Equal(items[1], target.SelectedItem);
  135. Assert.Equal(1, target.SelectedIndex);
  136. target.SelectedItem = new Item();
  137. Assert.Equal(null, target.SelectedItem);
  138. Assert.Equal(-1, target.SelectedIndex);
  139. }
  140. [Fact]
  141. public void Setting_SelectedIndex_Should_Set_SelectedItem()
  142. {
  143. var items = new[]
  144. {
  145. new Item(),
  146. new Item(),
  147. };
  148. var target = new SelectingItemsControl
  149. {
  150. Items = items,
  151. Template = Template(),
  152. };
  153. target.ApplyTemplate();
  154. target.SelectedIndex = 1;
  155. Assert.Equal(items[1], target.SelectedItem);
  156. }
  157. [Fact]
  158. public void Setting_SelectedIndex_Out_Of_Bounds_Should_Clear_Selection()
  159. {
  160. var items = new[]
  161. {
  162. new Item(),
  163. new Item(),
  164. };
  165. var target = new SelectingItemsControl
  166. {
  167. Items = items,
  168. Template = Template(),
  169. };
  170. target.ApplyTemplate();
  171. target.SelectedIndex = 2;
  172. Assert.Equal(-1, target.SelectedIndex);
  173. }
  174. [Fact]
  175. public void Setting_SelectedItem_To_Non_Existent_Item_Should_Clear_Selection()
  176. {
  177. var target = new SelectingItemsControl
  178. {
  179. Template = Template(),
  180. };
  181. target.ApplyTemplate();
  182. target.SelectedItem = new Item();
  183. Assert.Equal(-1, target.SelectedIndex);
  184. Assert.Null(target.SelectedItem);
  185. }
  186. [Fact]
  187. public void Adding_Selected_Item_Should_Update_Selection()
  188. {
  189. var items = new PerspexList<Item>(new[]
  190. {
  191. new Item(),
  192. new Item(),
  193. });
  194. var target = new SelectingItemsControl
  195. {
  196. Items = items,
  197. Template = Template(),
  198. };
  199. target.ApplyTemplate();
  200. items.Add(new Item { IsSelected = true });
  201. Assert.Equal(2, target.SelectedIndex);
  202. Assert.Equal(items[2], target.SelectedItem);
  203. }
  204. [Fact]
  205. public void Setting_Items_To_Null_Should_Clear_Selection()
  206. {
  207. var items = new PerspexList<Item>
  208. {
  209. new Item(),
  210. new Item(),
  211. };
  212. var target = new SelectingItemsControl
  213. {
  214. Items = items,
  215. Template = Template(),
  216. };
  217. target.ApplyTemplate();
  218. target.SelectedIndex = 1;
  219. Assert.Equal(items[1], target.SelectedItem);
  220. Assert.Equal(1, target.SelectedIndex);
  221. target.Items = null;
  222. Assert.Equal(null, target.SelectedItem);
  223. Assert.Equal(-1, target.SelectedIndex);
  224. }
  225. [Fact]
  226. public void Removing_Selected_Item_Should_Clear_Selection()
  227. {
  228. var items = new PerspexList<Item>
  229. {
  230. new Item(),
  231. new Item(),
  232. };
  233. var target = new SelectingItemsControl
  234. {
  235. Items = items,
  236. Template = Template(),
  237. };
  238. target.ApplyTemplate();
  239. target.SelectedIndex = 1;
  240. Assert.Equal(items[1], target.SelectedItem);
  241. Assert.Equal(1, target.SelectedIndex);
  242. items.RemoveAt(1);
  243. Assert.Equal(null, target.SelectedItem);
  244. Assert.Equal(-1, target.SelectedIndex);
  245. }
  246. [Fact]
  247. public void Resetting_Items_Collection_Should_Clear_Selection()
  248. {
  249. // Need to use ObservableCollection here as PerspexList signals a Clear as an
  250. // add + remove.
  251. var items = new ObservableCollection<Item>
  252. {
  253. new Item(),
  254. new Item(),
  255. };
  256. var target = new SelectingItemsControl
  257. {
  258. Items = items,
  259. Template = Template(),
  260. };
  261. target.ApplyTemplate();
  262. target.SelectedIndex = 1;
  263. Assert.Equal(items[1], target.SelectedItem);
  264. Assert.Equal(1, target.SelectedIndex);
  265. items.Clear();
  266. Assert.Equal(null, target.SelectedItem);
  267. Assert.Equal(-1, target.SelectedIndex);
  268. }
  269. [Fact]
  270. public void Focusing_Item_With_Pointer_Should_Select_It()
  271. {
  272. var target = new SelectingItemsControl
  273. {
  274. Template = Template(),
  275. Items = new[] { "foo", "bar" },
  276. };
  277. target.ApplyTemplate();
  278. var e = new GotFocusEventArgs
  279. {
  280. RoutedEvent = InputElement.GotFocusEvent,
  281. NavigationMethod = NavigationMethod.Pointer,
  282. };
  283. target.Presenter.Panel.Children[1].RaiseEvent(e);
  284. Assert.Equal(1, target.SelectedIndex);
  285. // GotFocus should be raised on parent control.
  286. Assert.False(e.Handled);
  287. }
  288. [Fact]
  289. public void Focusing_Item_With_Directional_Keys_Should_Select_It()
  290. {
  291. var target = new SelectingItemsControl
  292. {
  293. Template = Template(),
  294. Items = new[] { "foo", "bar" },
  295. };
  296. target.ApplyTemplate();
  297. var e = new GotFocusEventArgs
  298. {
  299. RoutedEvent = InputElement.GotFocusEvent,
  300. NavigationMethod = NavigationMethod.Directional,
  301. };
  302. target.Presenter.Panel.Children[1].RaiseEvent(e);
  303. Assert.Equal(1, target.SelectedIndex);
  304. Assert.False(e.Handled);
  305. }
  306. [Fact]
  307. public void Focusing_Item_With_Tab_Should_Not_Select_It()
  308. {
  309. var target = new SelectingItemsControl
  310. {
  311. Template = Template(),
  312. Items = new[] { "foo", "bar" },
  313. };
  314. target.ApplyTemplate();
  315. var e = new GotFocusEventArgs
  316. {
  317. RoutedEvent = InputElement.GotFocusEvent,
  318. NavigationMethod = NavigationMethod.Tab,
  319. };
  320. target.Presenter.Panel.Children[1].RaiseEvent(e);
  321. Assert.Equal(-1, target.SelectedIndex);
  322. }
  323. [Fact]
  324. public void Raising_IsSelectedChanged_On_Item_Should_Update_Selection()
  325. {
  326. var items = new[]
  327. {
  328. new Item(),
  329. new Item(),
  330. };
  331. var target = new SelectingItemsControl
  332. {
  333. Items = items,
  334. Template = Template(),
  335. };
  336. target.ApplyTemplate();
  337. target.SelectedItem = items[1];
  338. Assert.False(items[0].IsSelected);
  339. Assert.True(items[1].IsSelected);
  340. items[0].IsSelected = true;
  341. items[0].RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
  342. Assert.Equal(0, target.SelectedIndex);
  343. Assert.Equal(items[0], target.SelectedItem);
  344. Assert.True(items[0].IsSelected);
  345. Assert.False(items[1].IsSelected);
  346. }
  347. [Fact]
  348. public void Clearing_IsSelected_And_Raising_IsSelectedChanged_On_Item_Should_Update_Selection()
  349. {
  350. var items = new[]
  351. {
  352. new Item(),
  353. new Item(),
  354. };
  355. var target = new SelectingItemsControl
  356. {
  357. Items = items,
  358. Template = Template(),
  359. };
  360. target.ApplyTemplate();
  361. target.SelectedItem = items[1];
  362. Assert.False(items[0].IsSelected);
  363. Assert.True(items[1].IsSelected);
  364. items[1].IsSelected = false;
  365. items[1].RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
  366. Assert.Equal(-1, target.SelectedIndex);
  367. Assert.Null(target.SelectedItem);
  368. }
  369. [Fact]
  370. public void Raising_IsSelectedChanged_On_Someone_Elses_Item_Should_Not_Update_Selection()
  371. {
  372. var items = new[]
  373. {
  374. new Item(),
  375. new Item(),
  376. };
  377. var target = new SelectingItemsControl
  378. {
  379. Items = items,
  380. Template = Template(),
  381. };
  382. target.ApplyTemplate();
  383. target.SelectedItem = items[1];
  384. var notChild = new Item
  385. {
  386. IsSelected = true,
  387. };
  388. target.RaiseEvent(new RoutedEventArgs
  389. {
  390. RoutedEvent = SelectingItemsControl.IsSelectedChangedEvent,
  391. Source = notChild,
  392. });
  393. Assert.Equal(target.SelectedItem, items[1]);
  394. }
  395. private ControlTemplate Template()
  396. {
  397. return new ControlTemplate<SelectingItemsControl>(control =>
  398. new ItemsPresenter
  399. {
  400. Name = "itemsPresenter",
  401. [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty],
  402. [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty],
  403. });
  404. }
  405. private class Item : Control, ISelectable
  406. {
  407. public bool IsSelected { get; set; }
  408. }
  409. }
  410. }