SelectingItemsControlTests.cs 35 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261
  1. // Copyright (c) The Avalonia 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;
  4. using System.Collections.Generic;
  5. using System.Collections.ObjectModel;
  6. using System.Collections.Specialized;
  7. using System.ComponentModel;
  8. using System.Linq;
  9. using Avalonia.Collections;
  10. using Avalonia.Controls.Presenters;
  11. using Avalonia.Controls.Primitives;
  12. using Avalonia.Controls.Templates;
  13. using Avalonia.Data;
  14. using Avalonia.Input;
  15. using Avalonia.Interactivity;
  16. using Avalonia.Markup.Data;
  17. using Avalonia.Styling;
  18. using Avalonia.UnitTests;
  19. using Moq;
  20. using Xunit;
  21. namespace Avalonia.Controls.UnitTests.Primitives
  22. {
  23. public class SelectingItemsControlTests
  24. {
  25. private MouseTestHelper _helper = new MouseTestHelper();
  26. [Fact]
  27. public void SelectedIndex_Should_Initially_Be_Minus_1()
  28. {
  29. var items = new[]
  30. {
  31. new Item(),
  32. new Item(),
  33. };
  34. var target = new SelectingItemsControl
  35. {
  36. Items = items,
  37. Template = Template(),
  38. };
  39. Assert.Equal(-1, target.SelectedIndex);
  40. }
  41. [Fact]
  42. public void Item_IsSelected_Should_Initially_Be_False()
  43. {
  44. var items = new[]
  45. {
  46. new Item(),
  47. new Item(),
  48. };
  49. var target = new SelectingItemsControl
  50. {
  51. Items = items,
  52. Template = Template(),
  53. };
  54. target.ApplyTemplate();
  55. Assert.False(items[0].IsSelected);
  56. Assert.False(items[1].IsSelected);
  57. }
  58. [Fact]
  59. public void Setting_SelectedItem_Should_Set_Item_IsSelected_True()
  60. {
  61. var items = new[]
  62. {
  63. new Item(),
  64. new Item(),
  65. };
  66. var target = new SelectingItemsControl
  67. {
  68. Items = items,
  69. Template = Template(),
  70. };
  71. target.ApplyTemplate();
  72. target.Presenter.ApplyTemplate();
  73. target.SelectedItem = items[1];
  74. Assert.False(items[0].IsSelected);
  75. Assert.True(items[1].IsSelected);
  76. }
  77. [Fact]
  78. public void Setting_SelectedItem_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
  79. {
  80. var items = new[]
  81. {
  82. new Item(),
  83. new Item(),
  84. };
  85. var target = new SelectingItemsControl
  86. {
  87. Items = items,
  88. Template = Template(),
  89. };
  90. target.SelectedItem = items[1];
  91. target.ApplyTemplate();
  92. target.Presenter.ApplyTemplate();
  93. Assert.False(items[0].IsSelected);
  94. Assert.True(items[1].IsSelected);
  95. }
  96. [Fact]
  97. public void SelectedIndex_Should_Be_Minus_1_After_Initialize()
  98. {
  99. var items = new[]
  100. {
  101. new Item(),
  102. new Item(),
  103. };
  104. var target = new ListBox();
  105. target.BeginInit();
  106. target.Items = items;
  107. target.Template = Template();
  108. target.EndInit();
  109. Assert.Equal(-1, target.SelectedIndex);
  110. }
  111. [Fact]
  112. public void SelectedIndex_Should_Be_0_After_Initialize_With_AlwaysSelected()
  113. {
  114. var items = new[]
  115. {
  116. new Item(),
  117. new Item(),
  118. };
  119. var target = new ListBox();
  120. target.BeginInit();
  121. target.SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected;
  122. target.Items = items;
  123. target.Template = Template();
  124. target.EndInit();
  125. Assert.Equal(0, target.SelectedIndex);
  126. }
  127. [Fact]
  128. public void Setting_SelectedIndex_During_Initialize_Should_Select_Item_When_AlwaysSelected_Is_Used()
  129. {
  130. var listBox = new ListBox
  131. {
  132. SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected
  133. };
  134. listBox.BeginInit();
  135. listBox.SelectedIndex = 1;
  136. var items = new AvaloniaList<string>();
  137. listBox.Items = items;
  138. items.Add("A");
  139. items.Add("B");
  140. items.Add("C");
  141. listBox.EndInit();
  142. Assert.Equal("B", listBox.SelectedItem);
  143. }
  144. [Fact]
  145. public void Setting_SelectedIndex_Before_Initialize_Should_Retain()
  146. {
  147. var listBox = new ListBox
  148. {
  149. SelectionMode = SelectionMode.Single,
  150. Items = new[] { "foo", "bar", "baz" },
  151. SelectedIndex = 1
  152. };
  153. listBox.BeginInit();
  154. listBox.EndInit();
  155. Assert.Equal(1, listBox.SelectedIndex);
  156. Assert.Equal("bar", listBox.SelectedItem);
  157. }
  158. [Fact]
  159. public void Setting_SelectedIndex_During_Initialize_Should_Take_Priority_Over_Previous_Value()
  160. {
  161. var listBox = new ListBox
  162. {
  163. SelectionMode = SelectionMode.Single,
  164. Items = new[] { "foo", "bar", "baz" },
  165. SelectedIndex = 2
  166. };
  167. listBox.BeginInit();
  168. listBox.SelectedIndex = 1;
  169. listBox.EndInit();
  170. Assert.Equal(1, listBox.SelectedIndex);
  171. Assert.Equal("bar", listBox.SelectedItem);
  172. }
  173. [Fact]
  174. public void Setting_SelectedItem_Before_Initialize_Should_Retain()
  175. {
  176. var listBox = new ListBox
  177. {
  178. SelectionMode = SelectionMode.Single,
  179. Items = new[] { "foo", "bar", "baz" },
  180. SelectedItem = "bar"
  181. };
  182. listBox.BeginInit();
  183. listBox.EndInit();
  184. Assert.Equal(1, listBox.SelectedIndex);
  185. Assert.Equal("bar", listBox.SelectedItem);
  186. }
  187. [Fact]
  188. public void Setting_SelectedItems_Before_Initialize_Should_Retain()
  189. {
  190. var listBox = new ListBox
  191. {
  192. SelectionMode = SelectionMode.Multiple,
  193. Items = new[] { "foo", "bar", "baz" },
  194. };
  195. var selected = new[] { "foo", "bar" };
  196. foreach (var v in selected)
  197. {
  198. listBox.SelectedItems.Add(v);
  199. }
  200. listBox.BeginInit();
  201. listBox.EndInit();
  202. Assert.Equal(selected, listBox.SelectedItems);
  203. }
  204. [Fact]
  205. public void Setting_SelectedItems_During_Initialize_Should_Take_Priority_Over_Previous_Value()
  206. {
  207. var listBox = new ListBox
  208. {
  209. SelectionMode = SelectionMode.Multiple,
  210. Items = new[] { "foo", "bar", "baz" },
  211. };
  212. var selected = new[] { "foo", "bar" };
  213. foreach (var v in new[] { "bar", "baz" })
  214. {
  215. listBox.SelectedItems.Add(v);
  216. }
  217. listBox.BeginInit();
  218. listBox.SelectedItems = new AvaloniaList<object>(selected);
  219. listBox.EndInit();
  220. Assert.Equal(selected, listBox.SelectedItems);
  221. }
  222. [Fact]
  223. public void Setting_SelectedIndex_Before_Initialize_With_AlwaysSelected_Should_Retain()
  224. {
  225. var listBox = new ListBox
  226. {
  227. SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected,
  228. Items = new[] { "foo", "bar", "baz" },
  229. SelectedIndex = 1
  230. };
  231. listBox.BeginInit();
  232. listBox.EndInit();
  233. Assert.Equal(1, listBox.SelectedIndex);
  234. Assert.Equal("bar", listBox.SelectedItem);
  235. }
  236. [Fact]
  237. public void Setting_SelectedIndex_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
  238. {
  239. var items = new[]
  240. {
  241. new Item(),
  242. new Item(),
  243. };
  244. var target = new SelectingItemsControl
  245. {
  246. Items = items,
  247. Template = Template(),
  248. };
  249. target.SelectedIndex = 1;
  250. target.ApplyTemplate();
  251. target.Presenter.ApplyTemplate();
  252. Assert.False(items[0].IsSelected);
  253. Assert.True(items[1].IsSelected);
  254. }
  255. [Fact]
  256. public void Setting_SelectedItem_Should_Set_SelectedIndex()
  257. {
  258. var items = new[]
  259. {
  260. new Item(),
  261. new Item(),
  262. };
  263. var target = new SelectingItemsControl
  264. {
  265. Items = items,
  266. Template = Template(),
  267. };
  268. target.ApplyTemplate();
  269. target.SelectedItem = items[1];
  270. Assert.Equal(items[1], target.SelectedItem);
  271. Assert.Equal(1, target.SelectedIndex);
  272. }
  273. [Fact]
  274. public void SelectedIndex_Item_Is_Updated_As_Items_Removed_When_Last_Item_Is_Selected()
  275. {
  276. var items = new ObservableCollection<string>
  277. {
  278. "Foo",
  279. "Bar",
  280. "FooBar"
  281. };
  282. var target = new SelectingItemsControl
  283. {
  284. Items = items,
  285. Template = Template(),
  286. };
  287. target.ApplyTemplate();
  288. target.SelectedItem = items[2];
  289. Assert.Equal(items[2], target.SelectedItem);
  290. Assert.Equal(2, target.SelectedIndex);
  291. items.RemoveAt(0);
  292. Assert.Equal(items[1], target.SelectedItem);
  293. Assert.Equal(1, target.SelectedIndex);
  294. }
  295. [Fact]
  296. public void Setting_SelectedItem_To_Not_Present_Item_Should_Clear_Selection()
  297. {
  298. var items = new[]
  299. {
  300. new Item(),
  301. new Item(),
  302. };
  303. var target = new SelectingItemsControl
  304. {
  305. Items = items,
  306. Template = Template(),
  307. };
  308. target.ApplyTemplate();
  309. target.SelectedItem = items[1];
  310. Assert.Equal(items[1], target.SelectedItem);
  311. Assert.Equal(1, target.SelectedIndex);
  312. target.SelectedItem = new Item();
  313. Assert.Null(target.SelectedItem);
  314. Assert.Equal(-1, target.SelectedIndex);
  315. }
  316. [Fact]
  317. public void Setting_SelectedIndex_Should_Set_SelectedItem()
  318. {
  319. var items = new[]
  320. {
  321. new Item(),
  322. new Item(),
  323. };
  324. var target = new SelectingItemsControl
  325. {
  326. Items = items,
  327. Template = Template(),
  328. };
  329. target.ApplyTemplate();
  330. target.SelectedIndex = 1;
  331. Assert.Equal(items[1], target.SelectedItem);
  332. }
  333. [Fact]
  334. public void Setting_SelectedIndex_Out_Of_Bounds_Should_Clear_Selection()
  335. {
  336. var items = new[]
  337. {
  338. new Item(),
  339. new Item(),
  340. };
  341. var target = new SelectingItemsControl
  342. {
  343. Items = items,
  344. Template = Template(),
  345. };
  346. target.ApplyTemplate();
  347. target.SelectedIndex = 2;
  348. Assert.Equal(-1, target.SelectedIndex);
  349. }
  350. [Fact]
  351. public void Setting_SelectedItem_To_Non_Existent_Item_Should_Clear_Selection()
  352. {
  353. var target = new SelectingItemsControl
  354. {
  355. Template = Template(),
  356. };
  357. target.ApplyTemplate();
  358. target.SelectedItem = new Item();
  359. Assert.Equal(-1, target.SelectedIndex);
  360. Assert.Null(target.SelectedItem);
  361. }
  362. [Fact]
  363. public void Adding_Selected_Item_Should_Update_Selection()
  364. {
  365. var items = new AvaloniaList<Item>(new[]
  366. {
  367. new Item(),
  368. new Item(),
  369. });
  370. var target = new SelectingItemsControl
  371. {
  372. Items = items,
  373. Template = Template(),
  374. };
  375. target.ApplyTemplate();
  376. target.Presenter.ApplyTemplate();
  377. items.Add(new Item { IsSelected = true });
  378. Assert.Equal(2, target.SelectedIndex);
  379. Assert.Equal(items[2], target.SelectedItem);
  380. }
  381. [Fact]
  382. public void Setting_Items_To_Null_Should_Clear_Selection()
  383. {
  384. var items = new AvaloniaList<Item>
  385. {
  386. new Item(),
  387. new Item(),
  388. };
  389. var target = new SelectingItemsControl
  390. {
  391. Items = items,
  392. Template = Template(),
  393. };
  394. target.ApplyTemplate();
  395. target.SelectedIndex = 1;
  396. Assert.Equal(items[1], target.SelectedItem);
  397. Assert.Equal(1, target.SelectedIndex);
  398. target.Items = null;
  399. Assert.Null(target.SelectedItem);
  400. Assert.Equal(-1, target.SelectedIndex);
  401. }
  402. [Fact]
  403. public void Removing_Selected_Item_Should_Clear_Selection()
  404. {
  405. var items = new AvaloniaList<Item>
  406. {
  407. new Item(),
  408. new Item(),
  409. };
  410. var target = new SelectingItemsControl
  411. {
  412. Items = items,
  413. Template = Template(),
  414. };
  415. target.ApplyTemplate();
  416. target.SelectedIndex = 1;
  417. Assert.Equal(items[1], target.SelectedItem);
  418. Assert.Equal(1, target.SelectedIndex);
  419. items.RemoveAt(1);
  420. Assert.Null(target.SelectedItem);
  421. Assert.Equal(-1, target.SelectedIndex);
  422. }
  423. [Fact]
  424. public void Moving_Selected_Item_Should_Update_Selection()
  425. {
  426. var items = new AvaloniaList<Item>
  427. {
  428. new Item(),
  429. new Item(),
  430. };
  431. var target = new SelectingItemsControl
  432. {
  433. Items = items,
  434. Template = Template(),
  435. };
  436. target.ApplyTemplate();
  437. target.SelectedIndex = 0;
  438. Assert.Equal(items[0], target.SelectedItem);
  439. Assert.Equal(0, target.SelectedIndex);
  440. items.Move(0, 1);
  441. Assert.Equal(items[1], target.SelectedItem);
  442. Assert.Equal(1, target.SelectedIndex);
  443. }
  444. [Fact]
  445. public void Resetting_Items_Collection_Should_Clear_Selection()
  446. {
  447. // Need to use ObservableCollection here as AvaloniaList signals a Clear as an
  448. // add + remove.
  449. var items = new ObservableCollection<Item>
  450. {
  451. new Item(),
  452. new Item(),
  453. };
  454. var target = new SelectingItemsControl
  455. {
  456. Items = items,
  457. Template = Template(),
  458. };
  459. target.ApplyTemplate();
  460. target.SelectedIndex = 1;
  461. Assert.Equal(items[1], target.SelectedItem);
  462. Assert.Equal(1, target.SelectedIndex);
  463. items.Clear();
  464. Assert.Null(target.SelectedItem);
  465. Assert.Equal(-1, target.SelectedIndex);
  466. }
  467. [Fact]
  468. public void Raising_IsSelectedChanged_On_Item_Should_Update_Selection()
  469. {
  470. var items = new[]
  471. {
  472. new Item(),
  473. new Item(),
  474. };
  475. var target = new SelectingItemsControl
  476. {
  477. Items = items,
  478. Template = Template(),
  479. };
  480. target.ApplyTemplate();
  481. target.Presenter.ApplyTemplate();
  482. target.SelectedItem = items[1];
  483. Assert.False(items[0].IsSelected);
  484. Assert.True(items[1].IsSelected);
  485. items[0].IsSelected = true;
  486. items[0].RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
  487. Assert.Equal(0, target.SelectedIndex);
  488. Assert.Equal(items[0], target.SelectedItem);
  489. Assert.True(items[0].IsSelected);
  490. Assert.False(items[1].IsSelected);
  491. }
  492. [Fact]
  493. public void Clearing_IsSelected_And_Raising_IsSelectedChanged_On_Item_Should_Update_Selection()
  494. {
  495. var items = new[]
  496. {
  497. new Item(),
  498. new Item(),
  499. };
  500. var target = new SelectingItemsControl
  501. {
  502. Items = items,
  503. Template = Template(),
  504. };
  505. target.ApplyTemplate();
  506. target.Presenter.ApplyTemplate();
  507. target.SelectedItem = items[1];
  508. Assert.False(items[0].IsSelected);
  509. Assert.True(items[1].IsSelected);
  510. items[1].IsSelected = false;
  511. items[1].RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
  512. Assert.Equal(-1, target.SelectedIndex);
  513. Assert.Null(target.SelectedItem);
  514. }
  515. [Fact]
  516. public void Raising_IsSelectedChanged_On_Someone_Elses_Item_Should_Not_Update_Selection()
  517. {
  518. var items = new[]
  519. {
  520. new Item(),
  521. new Item(),
  522. };
  523. var target = new SelectingItemsControl
  524. {
  525. Items = items,
  526. Template = Template(),
  527. };
  528. target.ApplyTemplate();
  529. target.SelectedItem = items[1];
  530. var notChild = new Item
  531. {
  532. IsSelected = true,
  533. };
  534. target.RaiseEvent(new RoutedEventArgs
  535. {
  536. RoutedEvent = SelectingItemsControl.IsSelectedChangedEvent,
  537. Source = notChild,
  538. });
  539. Assert.Equal(target.SelectedItem, items[1]);
  540. }
  541. [Fact]
  542. public void Setting_SelectedIndex_Should_Raise_SelectionChanged_Event()
  543. {
  544. var items = new[]
  545. {
  546. new Item(),
  547. new Item(),
  548. };
  549. var target = new SelectingItemsControl
  550. {
  551. Items = items,
  552. Template = Template(),
  553. };
  554. var called = false;
  555. target.SelectionChanged += (s, e) =>
  556. {
  557. Assert.Same(items[1], e.AddedItems.Cast<object>().Single());
  558. Assert.Empty(e.RemovedItems);
  559. called = true;
  560. };
  561. target.SelectedIndex = 1;
  562. Assert.True(called);
  563. }
  564. [Fact]
  565. public void Clearing_SelectedIndex_Should_Raise_SelectionChanged_Event()
  566. {
  567. var items = new[]
  568. {
  569. new Item(),
  570. new Item(),
  571. };
  572. var target = new SelectingItemsControl
  573. {
  574. Items = items,
  575. Template = Template(),
  576. SelectedIndex = 1,
  577. };
  578. target.ApplyTemplate();
  579. target.Presenter.ApplyTemplate();
  580. var called = false;
  581. target.SelectionChanged += (s, e) =>
  582. {
  583. Assert.Same(items[1], e.RemovedItems.Cast<object>().Single());
  584. Assert.Empty(e.AddedItems);
  585. called = true;
  586. };
  587. target.SelectedIndex = -1;
  588. Assert.True(called);
  589. }
  590. [Fact]
  591. public void Order_Of_Setting_Items_And_SelectedIndex_During_Initialization_Should_Not_Matter()
  592. {
  593. var items = new[] { "Foo", "Bar" };
  594. var target = new SelectingItemsControl();
  595. ((ISupportInitialize)target).BeginInit();
  596. target.SelectedIndex = 1;
  597. target.Items = items;
  598. ((ISupportInitialize)target).EndInit();
  599. Assert.Equal(1, target.SelectedIndex);
  600. Assert.Equal("Bar", target.SelectedItem);
  601. }
  602. [Fact]
  603. public void Order_Of_Setting_Items_And_SelectedItem_During_Initialization_Should_Not_Matter()
  604. {
  605. var items = new[] { "Foo", "Bar" };
  606. var target = new SelectingItemsControl();
  607. ((ISupportInitialize)target).BeginInit();
  608. target.SelectedItem = "Bar";
  609. target.Items = items;
  610. ((ISupportInitialize)target).EndInit();
  611. Assert.Equal(1, target.SelectedIndex);
  612. Assert.Equal("Bar", target.SelectedItem);
  613. }
  614. [Fact]
  615. public void Changing_DataContext_Should_Not_Clear_Nested_ViewModel_SelectedItem()
  616. {
  617. var items = new[]
  618. {
  619. new Item(),
  620. new Item(),
  621. };
  622. var vm = new MasterViewModel
  623. {
  624. Child = new ChildViewModel
  625. {
  626. Items = items,
  627. SelectedItem = items[1],
  628. }
  629. };
  630. var target = new SelectingItemsControl { DataContext = vm };
  631. var itemsBinding = new Binding("Child.Items");
  632. var selectedBinding = new Binding("Child.SelectedItem");
  633. target.Bind(SelectingItemsControl.ItemsProperty, itemsBinding);
  634. target.Bind(SelectingItemsControl.SelectedItemProperty, selectedBinding);
  635. Assert.Equal(1, target.SelectedIndex);
  636. Assert.Same(vm.Child.SelectedItem, target.SelectedItem);
  637. items = new[]
  638. {
  639. new Item { Value = "Item1" },
  640. new Item { Value = "Item2" },
  641. new Item { Value = "Item3" },
  642. };
  643. vm = new MasterViewModel
  644. {
  645. Child = new ChildViewModel
  646. {
  647. Items = items,
  648. SelectedItem = items[2],
  649. }
  650. };
  651. target.DataContext = vm;
  652. Assert.Equal(2, target.SelectedIndex);
  653. Assert.Same(vm.Child.SelectedItem, target.SelectedItem);
  654. }
  655. [Fact]
  656. public void Nested_ListBox_Does_Not_Change_Parent_SelectedIndex()
  657. {
  658. SelectingItemsControl nested;
  659. var root = new SelectingItemsControl
  660. {
  661. Template = Template(),
  662. Items = new IControl[]
  663. {
  664. new Border(),
  665. nested = new ListBox
  666. {
  667. Template = Template(),
  668. Items = new[] { "foo", "bar" },
  669. SelectedIndex = 1,
  670. }
  671. },
  672. SelectedIndex = 0,
  673. };
  674. root.ApplyTemplate();
  675. root.Presenter.ApplyTemplate();
  676. nested.ApplyTemplate();
  677. nested.Presenter.ApplyTemplate();
  678. Assert.Equal(0, root.SelectedIndex);
  679. Assert.Equal(1, nested.SelectedIndex);
  680. nested.SelectedIndex = 0;
  681. Assert.Equal(0, root.SelectedIndex);
  682. }
  683. [Fact]
  684. public void Setting_SelectedItem_With_Pointer_Should_Set_TabOnceActiveElement()
  685. {
  686. var target = new ListBox
  687. {
  688. Template = Template(),
  689. Items = new[] { "Foo", "Bar", "Baz " },
  690. };
  691. target.ApplyTemplate();
  692. target.Presenter.ApplyTemplate();
  693. _helper.Down((Interactive)target.Presenter.Panel.Children[1]);
  694. var panel = target.Presenter.Panel;
  695. Assert.Equal(
  696. KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel),
  697. panel.Children[1]);
  698. }
  699. [Fact]
  700. public void Removing_SelectedItem_Should_Clear_TabOnceActiveElement()
  701. {
  702. var items = new ObservableCollection<string>(new[] { "Foo", "Bar", "Baz " });
  703. var target = new ListBox
  704. {
  705. Template = Template(),
  706. Items = items,
  707. };
  708. target.ApplyTemplate();
  709. target.Presenter.ApplyTemplate();
  710. _helper.Down(target.Presenter.Panel.Children[1]);
  711. items.RemoveAt(1);
  712. var panel = target.Presenter.Panel;
  713. Assert.Null(KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel));
  714. }
  715. [Fact]
  716. public void Resetting_Items_Collection_Should_Retain_Selection()
  717. {
  718. var itemsMock = new Mock<List<string>>();
  719. var itemsMockAsINCC = itemsMock.As<INotifyCollectionChanged>();
  720. itemsMock.Object.AddRange(new[] { "Foo", "Bar", "Baz" });
  721. var target = new SelectingItemsControl
  722. {
  723. Items = itemsMock.Object
  724. };
  725. target.SelectedIndex = 1;
  726. itemsMockAsINCC.Raise(e => e.CollectionChanged += null, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  727. Assert.True(target.SelectedIndex == 1);
  728. }
  729. [Fact]
  730. public void Binding_With_DelayedBinding_And_Initialization_Where_DataContext_Is_Root_Works()
  731. {
  732. // Test for #1932.
  733. var root = new RootWithItems();
  734. root.BeginInit();
  735. root.DataContext = root;
  736. var target = new ListBox();
  737. target.BeginInit();
  738. root.Child = target;
  739. DelayedBinding.Add(target, ItemsControl.ItemsProperty, new Binding(nameof(RootWithItems.Items)));
  740. DelayedBinding.Add(target, ListBox.SelectedItemProperty, new Binding(nameof(RootWithItems.Selected)));
  741. target.EndInit();
  742. root.EndInit();
  743. Assert.Equal("b", target.SelectedItem);
  744. }
  745. [Fact]
  746. public void Mode_For_SelectedIndex_Is_TwoWay_By_Default()
  747. {
  748. var items = new[]
  749. {
  750. new Item(),
  751. new Item(),
  752. new Item(),
  753. };
  754. var vm = new MasterViewModel
  755. {
  756. Child = new ChildViewModel
  757. {
  758. Items = items,
  759. SelectedIndex = 1,
  760. }
  761. };
  762. var target = new SelectingItemsControl { DataContext = vm };
  763. var itemsBinding = new Binding("Child.Items");
  764. var selectedIndBinding = new Binding("Child.SelectedIndex");
  765. target.Bind(SelectingItemsControl.ItemsProperty, itemsBinding);
  766. target.Bind(SelectingItemsControl.SelectedIndexProperty, selectedIndBinding);
  767. Assert.Equal(1, target.SelectedIndex);
  768. target.SelectedIndex = 2;
  769. Assert.Equal(2, target.SelectedIndex);
  770. Assert.Equal(2, vm.Child.SelectedIndex);
  771. }
  772. [Fact]
  773. public void Should_Select_Correct_Item_When_Duplicate_Items_Are_Present()
  774. {
  775. var target = new ListBox
  776. {
  777. Template = Template(),
  778. Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
  779. };
  780. target.ApplyTemplate();
  781. target.Presenter.ApplyTemplate();
  782. _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
  783. Assert.Equal(3, target.SelectedIndex);
  784. }
  785. [Fact]
  786. public void Should_Apply_Selected_Pseudoclass_To_Correct_Item_When_Duplicate_Items_Are_Present()
  787. {
  788. var target = new ListBox
  789. {
  790. Template = Template(),
  791. Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
  792. };
  793. target.ApplyTemplate();
  794. target.Presenter.ApplyTemplate();
  795. _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
  796. Assert.Equal(new[] { ":selected" }, target.Presenter.Panel.Children[3].Classes);
  797. }
  798. [Fact]
  799. public void Adding_Item_Before_SelectedItem_Should_Update_SelectedIndex()
  800. {
  801. var items = new ObservableCollection<string>
  802. {
  803. "Foo",
  804. "Bar",
  805. "Baz"
  806. };
  807. var target = new ListBox
  808. {
  809. Template = Template(),
  810. Items = items,
  811. SelectedIndex = 1,
  812. };
  813. target.ApplyTemplate();
  814. target.Presenter.ApplyTemplate();
  815. items.Insert(0, "Qux");
  816. Assert.Equal(2, target.SelectedIndex);
  817. Assert.Equal("Bar", target.SelectedItem);
  818. }
  819. [Fact]
  820. public void Removing_Item_Before_SelectedItem_Should_Update_SelectedIndex()
  821. {
  822. var items = new ObservableCollection<string>
  823. {
  824. "Foo",
  825. "Bar",
  826. "Baz"
  827. };
  828. var target = new ListBox
  829. {
  830. Template = Template(),
  831. Items = items,
  832. SelectedIndex = 1,
  833. };
  834. target.ApplyTemplate();
  835. target.Presenter.ApplyTemplate();
  836. items.RemoveAt(0);
  837. Assert.Equal(0, target.SelectedIndex);
  838. Assert.Equal("Bar", target.SelectedItem);
  839. }
  840. [Fact]
  841. public void Replacing_Selected_Item_Should_Update_SelectedItem()
  842. {
  843. var items = new ObservableCollection<string>
  844. {
  845. "Foo",
  846. "Bar",
  847. "Baz"
  848. };
  849. var target = new ListBox
  850. {
  851. Template = Template(),
  852. Items = items,
  853. SelectedIndex = 1,
  854. };
  855. target.ApplyTemplate();
  856. target.Presenter.ApplyTemplate();
  857. items[1] = "Qux";
  858. Assert.Equal(1, target.SelectedIndex);
  859. Assert.Equal("Qux", target.SelectedItem);
  860. }
  861. [Fact]
  862. public void AutoScrollToSelectedItem_Causes_Scroll_To_SelectedItem()
  863. {
  864. var items = new ObservableCollection<string>
  865. {
  866. "Foo",
  867. "Bar",
  868. "Baz"
  869. };
  870. var target = new ListBox
  871. {
  872. Template = Template(),
  873. Items = items,
  874. };
  875. target.ApplyTemplate();
  876. target.Presenter.ApplyTemplate();
  877. var raised = false;
  878. target.AddHandler(Control.RequestBringIntoViewEvent, (s, e) => raised = true);
  879. target.SelectedIndex = 2;
  880. Assert.True(raised);
  881. }
  882. [Fact]
  883. public void AutoScrollToSelectedItem_On_Reset_Works()
  884. {
  885. // Issue #3148
  886. using (UnitTestApplication.Start(TestServices.StyledWindow))
  887. {
  888. var items = new ResettingCollection(100);
  889. var target = new ListBox
  890. {
  891. Items = items,
  892. ItemTemplate = new FuncDataTemplate<string>((x, _) =>
  893. new TextBlock
  894. {
  895. Text = x,
  896. Width = 100,
  897. Height = 10
  898. }),
  899. AutoScrollToSelectedItem = true,
  900. VirtualizationMode = ItemVirtualizationMode.Simple,
  901. };
  902. var root = new TestRoot(true, target);
  903. root.Measure(new Size(100, 100));
  904. root.Arrange(new Rect(0, 0, 100, 100));
  905. Assert.True(target.Presenter.Panel.Children.Count > 0);
  906. Assert.True(target.Presenter.Panel.Children.Count < 100);
  907. target.SelectedItem = "Item99";
  908. // #3148 triggered here.
  909. items.Reset(new[] { "Item99" });
  910. Assert.Equal(0, target.SelectedIndex);
  911. Assert.Equal(1, target.Presenter.Panel.Children.Count);
  912. }
  913. }
  914. [Fact]
  915. public void Can_Set_Both_SelectedItem_And_SelectedItems_During_Initialization()
  916. {
  917. // Issue #2969.
  918. var target = new ListBox();
  919. var selectedItems = new List<object>();
  920. target.BeginInit();
  921. target.Template = Template();
  922. target.Items = new[] { "Foo", "Bar", "Baz" };
  923. target.SelectedItems = selectedItems;
  924. target.SelectedItem = "Bar";
  925. target.EndInit();
  926. Assert.Equal("Bar", target.SelectedItem);
  927. Assert.Equal(1, target.SelectedIndex);
  928. Assert.Same(selectedItems, target.SelectedItems);
  929. Assert.Equal(new[] { "Bar" }, selectedItems);
  930. }
  931. [Fact]
  932. public void MoveSelection_Wrap_Does_Not_Hang_With_No_Focusable_Controls()
  933. {
  934. // Issue #3094.
  935. var target = new TestSelector
  936. {
  937. Template = Template(),
  938. Items = new[]
  939. {
  940. new ListBoxItem { Focusable = false },
  941. new ListBoxItem { Focusable = false },
  942. },
  943. SelectedIndex = 0,
  944. };
  945. target.Measure(new Size(100, 100));
  946. target.Arrange(new Rect(0, 0, 100, 100));
  947. target.MoveSelection(NavigationDirection.Next, true);
  948. }
  949. private FuncControlTemplate Template()
  950. {
  951. return new FuncControlTemplate<SelectingItemsControl>((control, scope) =>
  952. new ItemsPresenter
  953. {
  954. Name = "itemsPresenter",
  955. [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty],
  956. [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty],
  957. [~ItemsPresenter.VirtualizationModeProperty] = control[~ListBox.VirtualizationModeProperty],
  958. }.RegisterInNameScope(scope));
  959. }
  960. private class Item : Control, ISelectable
  961. {
  962. public string Value { get; set; }
  963. public bool IsSelected { get; set; }
  964. }
  965. private class MasterViewModel : NotifyingBase
  966. {
  967. private ChildViewModel _child;
  968. public ChildViewModel Child
  969. {
  970. get { return _child; }
  971. set
  972. {
  973. _child = value;
  974. RaisePropertyChanged();
  975. }
  976. }
  977. }
  978. private class ChildViewModel : NotifyingBase
  979. {
  980. public IList<Item> Items { get; set; }
  981. public Item SelectedItem { get; set; }
  982. public int SelectedIndex { get; set; }
  983. }
  984. private class RootWithItems : TestRoot
  985. {
  986. public List<string> Items { get; set; } = new List<string>() { "a", "b", "c", "d", "e" };
  987. public string Selected { get; set; } = "b";
  988. }
  989. private class TestSelector : SelectingItemsControl
  990. {
  991. public new bool MoveSelection(NavigationDirection direction, bool wrap)
  992. {
  993. return base.MoveSelection(direction, wrap);
  994. }
  995. }
  996. private class ResettingCollection : List<string>, INotifyCollectionChanged
  997. {
  998. public ResettingCollection(int itemCount)
  999. {
  1000. AddRange(Enumerable.Range(0, itemCount).Select(x => $"Item{x}"));
  1001. }
  1002. public void Reset(IEnumerable<string> items)
  1003. {
  1004. Clear();
  1005. AddRange(items);
  1006. CollectionChanged?.Invoke(
  1007. this,
  1008. new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  1009. }
  1010. public event NotifyCollectionChangedEventHandler CollectionChanged;
  1011. }
  1012. }
  1013. }