SelectingItemsControlTests.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942
  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.Generic;
  4. using System.Collections.ObjectModel;
  5. using System.Collections.Specialized;
  6. using System.ComponentModel;
  7. using System.Linq;
  8. using Avalonia.Collections;
  9. using Avalonia.Controls.Presenters;
  10. using Avalonia.Controls.Primitives;
  11. using Avalonia.Controls.Templates;
  12. using Avalonia.Data;
  13. using Avalonia.Input;
  14. using Avalonia.Interactivity;
  15. using Avalonia.Markup.Data;
  16. using Avalonia.UnitTests;
  17. using Moq;
  18. using Xunit;
  19. namespace Avalonia.Controls.UnitTests.Primitives
  20. {
  21. public class SelectingItemsControlTests
  22. {
  23. private MouseTestHelper _helper = new MouseTestHelper();
  24. [Fact]
  25. public void SelectedIndex_Should_Initially_Be_Minus_1()
  26. {
  27. var items = new[]
  28. {
  29. new Item(),
  30. new Item(),
  31. };
  32. var target = new SelectingItemsControl
  33. {
  34. Items = items,
  35. Template = Template(),
  36. };
  37. Assert.Equal(-1, target.SelectedIndex);
  38. }
  39. [Fact]
  40. public void Item_IsSelected_Should_Initially_Be_False()
  41. {
  42. var items = new[]
  43. {
  44. new Item(),
  45. new Item(),
  46. };
  47. var target = new SelectingItemsControl
  48. {
  49. Items = items,
  50. Template = Template(),
  51. };
  52. target.ApplyTemplate();
  53. Assert.False(items[0].IsSelected);
  54. Assert.False(items[1].IsSelected);
  55. }
  56. [Fact]
  57. public void Setting_SelectedItem_Should_Set_Item_IsSelected_True()
  58. {
  59. var items = new[]
  60. {
  61. new Item(),
  62. new Item(),
  63. };
  64. var target = new SelectingItemsControl
  65. {
  66. Items = items,
  67. Template = Template(),
  68. };
  69. target.ApplyTemplate();
  70. target.Presenter.ApplyTemplate();
  71. target.SelectedItem = items[1];
  72. Assert.False(items[0].IsSelected);
  73. Assert.True(items[1].IsSelected);
  74. }
  75. [Fact]
  76. public void Setting_SelectedItem_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
  77. {
  78. var items = new[]
  79. {
  80. new Item(),
  81. new Item(),
  82. };
  83. var target = new SelectingItemsControl
  84. {
  85. Items = items,
  86. Template = Template(),
  87. };
  88. target.SelectedItem = items[1];
  89. target.ApplyTemplate();
  90. target.Presenter.ApplyTemplate();
  91. Assert.False(items[0].IsSelected);
  92. Assert.True(items[1].IsSelected);
  93. }
  94. [Fact]
  95. public void Setting_SelectedIndex_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
  96. {
  97. var items = new[]
  98. {
  99. new Item(),
  100. new Item(),
  101. };
  102. var target = new SelectingItemsControl
  103. {
  104. Items = items,
  105. Template = Template(),
  106. };
  107. target.SelectedIndex = 1;
  108. target.ApplyTemplate();
  109. target.Presenter.ApplyTemplate();
  110. Assert.False(items[0].IsSelected);
  111. Assert.True(items[1].IsSelected);
  112. }
  113. [Fact]
  114. public void Setting_SelectedItem_Should_Set_SelectedIndex()
  115. {
  116. var items = new[]
  117. {
  118. new Item(),
  119. new Item(),
  120. };
  121. var target = new SelectingItemsControl
  122. {
  123. Items = items,
  124. Template = Template(),
  125. };
  126. target.ApplyTemplate();
  127. target.SelectedItem = items[1];
  128. Assert.Equal(items[1], target.SelectedItem);
  129. Assert.Equal(1, target.SelectedIndex);
  130. }
  131. [Fact]
  132. public void SelectedIndex_Item_Is_Updated_As_Items_Removed_When_Last_Item_Is_Selected()
  133. {
  134. var items = new ObservableCollection<string>
  135. {
  136. "Foo",
  137. "Bar",
  138. "FooBar"
  139. };
  140. var target = new SelectingItemsControl
  141. {
  142. Items = items,
  143. Template = Template(),
  144. };
  145. target.ApplyTemplate();
  146. target.SelectedItem = items[2];
  147. Assert.Equal(items[2], target.SelectedItem);
  148. Assert.Equal(2, target.SelectedIndex);
  149. items.RemoveAt(0);
  150. Assert.Equal(items[1], target.SelectedItem);
  151. Assert.Equal(1, target.SelectedIndex);
  152. }
  153. [Fact]
  154. public void Setting_SelectedItem_To_Not_Present_Item_Should_Clear_Selection()
  155. {
  156. var items = new[]
  157. {
  158. new Item(),
  159. new Item(),
  160. };
  161. var target = new SelectingItemsControl
  162. {
  163. Items = items,
  164. Template = Template(),
  165. };
  166. target.ApplyTemplate();
  167. target.SelectedItem = items[1];
  168. Assert.Equal(items[1], target.SelectedItem);
  169. Assert.Equal(1, target.SelectedIndex);
  170. target.SelectedItem = new Item();
  171. Assert.Null(target.SelectedItem);
  172. Assert.Equal(-1, target.SelectedIndex);
  173. }
  174. [Fact]
  175. public void Setting_SelectedIndex_Should_Set_SelectedItem()
  176. {
  177. var items = new[]
  178. {
  179. new Item(),
  180. new Item(),
  181. };
  182. var target = new SelectingItemsControl
  183. {
  184. Items = items,
  185. Template = Template(),
  186. };
  187. target.ApplyTemplate();
  188. target.SelectedIndex = 1;
  189. Assert.Equal(items[1], target.SelectedItem);
  190. }
  191. [Fact]
  192. public void Setting_SelectedIndex_Out_Of_Bounds_Should_Clear_Selection()
  193. {
  194. var items = new[]
  195. {
  196. new Item(),
  197. new Item(),
  198. };
  199. var target = new SelectingItemsControl
  200. {
  201. Items = items,
  202. Template = Template(),
  203. };
  204. target.ApplyTemplate();
  205. target.SelectedIndex = 2;
  206. Assert.Equal(-1, target.SelectedIndex);
  207. }
  208. [Fact]
  209. public void Setting_SelectedItem_To_Non_Existent_Item_Should_Clear_Selection()
  210. {
  211. var target = new SelectingItemsControl
  212. {
  213. Template = Template(),
  214. };
  215. target.ApplyTemplate();
  216. target.SelectedItem = new Item();
  217. Assert.Equal(-1, target.SelectedIndex);
  218. Assert.Null(target.SelectedItem);
  219. }
  220. [Fact]
  221. public void Adding_Selected_Item_Should_Update_Selection()
  222. {
  223. var items = new AvaloniaList<Item>(new[]
  224. {
  225. new Item(),
  226. new Item(),
  227. });
  228. var target = new SelectingItemsControl
  229. {
  230. Items = items,
  231. Template = Template(),
  232. };
  233. target.ApplyTemplate();
  234. target.Presenter.ApplyTemplate();
  235. items.Add(new Item { IsSelected = true });
  236. Assert.Equal(2, target.SelectedIndex);
  237. Assert.Equal(items[2], target.SelectedItem);
  238. }
  239. [Fact]
  240. public void Setting_Items_To_Null_Should_Clear_Selection()
  241. {
  242. var items = new AvaloniaList<Item>
  243. {
  244. new Item(),
  245. new Item(),
  246. };
  247. var target = new SelectingItemsControl
  248. {
  249. Items = items,
  250. Template = Template(),
  251. };
  252. target.ApplyTemplate();
  253. target.SelectedIndex = 1;
  254. Assert.Equal(items[1], target.SelectedItem);
  255. Assert.Equal(1, target.SelectedIndex);
  256. target.Items = null;
  257. Assert.Null(target.SelectedItem);
  258. Assert.Equal(-1, target.SelectedIndex);
  259. }
  260. [Fact]
  261. public void Removing_Selected_Item_Should_Clear_Selection()
  262. {
  263. var items = new AvaloniaList<Item>
  264. {
  265. new Item(),
  266. new Item(),
  267. };
  268. var target = new SelectingItemsControl
  269. {
  270. Items = items,
  271. Template = Template(),
  272. };
  273. target.ApplyTemplate();
  274. target.SelectedIndex = 1;
  275. Assert.Equal(items[1], target.SelectedItem);
  276. Assert.Equal(1, target.SelectedIndex);
  277. items.RemoveAt(1);
  278. Assert.Null(target.SelectedItem);
  279. Assert.Equal(-1, target.SelectedIndex);
  280. }
  281. [Fact]
  282. public void Moving_Selected_Item_Should_Update_Selection()
  283. {
  284. var items = new AvaloniaList<Item>
  285. {
  286. new Item(),
  287. new Item(),
  288. };
  289. var target = new SelectingItemsControl
  290. {
  291. Items = items,
  292. Template = Template(),
  293. };
  294. target.ApplyTemplate();
  295. target.SelectedIndex = 0;
  296. Assert.Equal(items[0], target.SelectedItem);
  297. Assert.Equal(0, target.SelectedIndex);
  298. items.Move(0, 1);
  299. Assert.Equal(items[1], target.SelectedItem);
  300. Assert.Equal(1, target.SelectedIndex);
  301. }
  302. [Fact]
  303. public void Resetting_Items_Collection_Should_Clear_Selection()
  304. {
  305. // Need to use ObservableCollection here as AvaloniaList signals a Clear as an
  306. // add + remove.
  307. var items = new ObservableCollection<Item>
  308. {
  309. new Item(),
  310. new Item(),
  311. };
  312. var target = new SelectingItemsControl
  313. {
  314. Items = items,
  315. Template = Template(),
  316. };
  317. target.ApplyTemplate();
  318. target.SelectedIndex = 1;
  319. Assert.Equal(items[1], target.SelectedItem);
  320. Assert.Equal(1, target.SelectedIndex);
  321. items.Clear();
  322. Assert.Null(target.SelectedItem);
  323. Assert.Equal(-1, target.SelectedIndex);
  324. }
  325. [Fact]
  326. public void Raising_IsSelectedChanged_On_Item_Should_Update_Selection()
  327. {
  328. var items = new[]
  329. {
  330. new Item(),
  331. new Item(),
  332. };
  333. var target = new SelectingItemsControl
  334. {
  335. Items = items,
  336. Template = Template(),
  337. };
  338. target.ApplyTemplate();
  339. target.Presenter.ApplyTemplate();
  340. target.SelectedItem = items[1];
  341. Assert.False(items[0].IsSelected);
  342. Assert.True(items[1].IsSelected);
  343. items[0].IsSelected = true;
  344. items[0].RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
  345. Assert.Equal(0, target.SelectedIndex);
  346. Assert.Equal(items[0], target.SelectedItem);
  347. Assert.True(items[0].IsSelected);
  348. Assert.False(items[1].IsSelected);
  349. }
  350. [Fact]
  351. public void Clearing_IsSelected_And_Raising_IsSelectedChanged_On_Item_Should_Update_Selection()
  352. {
  353. var items = new[]
  354. {
  355. new Item(),
  356. new Item(),
  357. };
  358. var target = new SelectingItemsControl
  359. {
  360. Items = items,
  361. Template = Template(),
  362. };
  363. target.ApplyTemplate();
  364. target.Presenter.ApplyTemplate();
  365. target.SelectedItem = items[1];
  366. Assert.False(items[0].IsSelected);
  367. Assert.True(items[1].IsSelected);
  368. items[1].IsSelected = false;
  369. items[1].RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
  370. Assert.Equal(-1, target.SelectedIndex);
  371. Assert.Null(target.SelectedItem);
  372. }
  373. [Fact]
  374. public void Raising_IsSelectedChanged_On_Someone_Elses_Item_Should_Not_Update_Selection()
  375. {
  376. var items = new[]
  377. {
  378. new Item(),
  379. new Item(),
  380. };
  381. var target = new SelectingItemsControl
  382. {
  383. Items = items,
  384. Template = Template(),
  385. };
  386. target.ApplyTemplate();
  387. target.SelectedItem = items[1];
  388. var notChild = new Item
  389. {
  390. IsSelected = true,
  391. };
  392. target.RaiseEvent(new RoutedEventArgs
  393. {
  394. RoutedEvent = SelectingItemsControl.IsSelectedChangedEvent,
  395. Source = notChild,
  396. });
  397. Assert.Equal(target.SelectedItem, items[1]);
  398. }
  399. [Fact]
  400. public void Setting_SelectedIndex_Should_Raise_SelectionChanged_Event()
  401. {
  402. var items = new[]
  403. {
  404. new Item(),
  405. new Item(),
  406. };
  407. var target = new SelectingItemsControl
  408. {
  409. Items = items,
  410. Template = Template(),
  411. };
  412. var called = false;
  413. target.SelectionChanged += (s, e) =>
  414. {
  415. Assert.Same(items[1], e.AddedItems.Cast<object>().Single());
  416. Assert.Empty(e.RemovedItems);
  417. called = true;
  418. };
  419. target.SelectedIndex = 1;
  420. Assert.True(called);
  421. }
  422. [Fact]
  423. public void Clearing_SelectedIndex_Should_Raise_SelectionChanged_Event()
  424. {
  425. var items = new[]
  426. {
  427. new Item(),
  428. new Item(),
  429. };
  430. var target = new SelectingItemsControl
  431. {
  432. Items = items,
  433. Template = Template(),
  434. SelectedIndex = 1,
  435. };
  436. target.ApplyTemplate();
  437. target.Presenter.ApplyTemplate();
  438. var called = false;
  439. target.SelectionChanged += (s, e) =>
  440. {
  441. Assert.Same(items[1], e.RemovedItems.Cast<object>().Single());
  442. Assert.Empty(e.AddedItems);
  443. called = true;
  444. };
  445. target.SelectedIndex = -1;
  446. Assert.True(called);
  447. }
  448. [Fact]
  449. public void Order_Of_Setting_Items_And_SelectedIndex_During_Initialization_Should_Not_Matter()
  450. {
  451. var items = new[] { "Foo", "Bar" };
  452. var target = new SelectingItemsControl();
  453. ((ISupportInitialize)target).BeginInit();
  454. target.SelectedIndex = 1;
  455. target.Items = items;
  456. ((ISupportInitialize)target).EndInit();
  457. Assert.Equal(1, target.SelectedIndex);
  458. Assert.Equal("Bar", target.SelectedItem);
  459. }
  460. [Fact]
  461. public void Order_Of_Setting_Items_And_SelectedItem_During_Initialization_Should_Not_Matter()
  462. {
  463. var items = new[] { "Foo", "Bar" };
  464. var target = new SelectingItemsControl();
  465. ((ISupportInitialize)target).BeginInit();
  466. target.SelectedItem = "Bar";
  467. target.Items = items;
  468. ((ISupportInitialize)target).EndInit();
  469. Assert.Equal(1, target.SelectedIndex);
  470. Assert.Equal("Bar", target.SelectedItem);
  471. }
  472. [Fact]
  473. public void Changing_DataContext_Should_Not_Clear_Nested_ViewModel_SelectedItem()
  474. {
  475. var items = new[]
  476. {
  477. new Item(),
  478. new Item(),
  479. };
  480. var vm = new MasterViewModel
  481. {
  482. Child = new ChildViewModel
  483. {
  484. Items = items,
  485. SelectedItem = items[1],
  486. }
  487. };
  488. var target = new SelectingItemsControl { DataContext = vm };
  489. var itemsBinding = new Binding("Child.Items");
  490. var selectedBinding = new Binding("Child.SelectedItem");
  491. target.Bind(SelectingItemsControl.ItemsProperty, itemsBinding);
  492. target.Bind(SelectingItemsControl.SelectedItemProperty, selectedBinding);
  493. Assert.Equal(1, target.SelectedIndex);
  494. Assert.Same(vm.Child.SelectedItem, target.SelectedItem);
  495. items = new[]
  496. {
  497. new Item { Value = "Item1" },
  498. new Item { Value = "Item2" },
  499. new Item { Value = "Item3" },
  500. };
  501. vm = new MasterViewModel
  502. {
  503. Child = new ChildViewModel
  504. {
  505. Items = items,
  506. SelectedItem = items[2],
  507. }
  508. };
  509. target.DataContext = vm;
  510. Assert.Equal(2, target.SelectedIndex);
  511. Assert.Same(vm.Child.SelectedItem, target.SelectedItem);
  512. }
  513. [Fact]
  514. public void Nested_ListBox_Does_Not_Change_Parent_SelectedIndex()
  515. {
  516. SelectingItemsControl nested;
  517. var root = new SelectingItemsControl
  518. {
  519. Template = Template(),
  520. Items = new IControl[]
  521. {
  522. new Border(),
  523. nested = new ListBox
  524. {
  525. Template = Template(),
  526. Items = new[] { "foo", "bar" },
  527. SelectedIndex = 1,
  528. }
  529. },
  530. SelectedIndex = 0,
  531. };
  532. root.ApplyTemplate();
  533. root.Presenter.ApplyTemplate();
  534. nested.ApplyTemplate();
  535. nested.Presenter.ApplyTemplate();
  536. Assert.Equal(0, root.SelectedIndex);
  537. Assert.Equal(1, nested.SelectedIndex);
  538. nested.SelectedIndex = 0;
  539. Assert.Equal(0, root.SelectedIndex);
  540. }
  541. [Fact]
  542. public void Setting_SelectedItem_With_Pointer_Should_Set_TabOnceActiveElement()
  543. {
  544. var target = new ListBox
  545. {
  546. Template = Template(),
  547. Items = new[] { "Foo", "Bar", "Baz " },
  548. };
  549. target.ApplyTemplate();
  550. target.Presenter.ApplyTemplate();
  551. _helper.Down((Interactive)target.Presenter.Panel.Children[1]);
  552. var panel = target.Presenter.Panel;
  553. Assert.Equal(
  554. KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel),
  555. panel.Children[1]);
  556. }
  557. [Fact]
  558. public void Removing_SelectedItem_Should_Clear_TabOnceActiveElement()
  559. {
  560. var items = new ObservableCollection<string>(new[] { "Foo", "Bar", "Baz " });
  561. var target = new ListBox
  562. {
  563. Template = Template(),
  564. Items = items,
  565. };
  566. target.ApplyTemplate();
  567. target.Presenter.ApplyTemplate();
  568. _helper.Down(target.Presenter.Panel.Children[1]);
  569. items.RemoveAt(1);
  570. var panel = target.Presenter.Panel;
  571. Assert.Null(KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel));
  572. }
  573. [Fact]
  574. public void Resetting_Items_Collection_Should_Retain_Selection()
  575. {
  576. var itemsMock = new Mock<List<string>>();
  577. var itemsMockAsINCC = itemsMock.As<INotifyCollectionChanged>();
  578. itemsMock.Object.AddRange(new[] { "Foo", "Bar", "Baz" });
  579. var target = new SelectingItemsControl
  580. {
  581. Items = itemsMock.Object
  582. };
  583. target.SelectedIndex = 1;
  584. itemsMockAsINCC.Raise(e => e.CollectionChanged += null, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  585. Assert.True(target.SelectedIndex == 1);
  586. }
  587. [Fact]
  588. public void Binding_With_DelayedBinding_And_Initialization_Where_DataContext_Is_Root_Works()
  589. {
  590. // Test for #1932.
  591. var root = new RootWithItems();
  592. root.BeginInit();
  593. root.DataContext = root;
  594. var target = new ListBox();
  595. target.BeginInit();
  596. root.Child = target;
  597. DelayedBinding.Add(target, ItemsControl.ItemsProperty, new Binding(nameof(RootWithItems.Items)));
  598. DelayedBinding.Add(target, ListBox.SelectedItemProperty, new Binding(nameof(RootWithItems.Selected)));
  599. target.EndInit();
  600. root.EndInit();
  601. Assert.Equal("b", target.SelectedItem);
  602. }
  603. [Fact]
  604. public void Mode_For_SelectedIndex_Is_TwoWay_By_Default()
  605. {
  606. var items = new[]
  607. {
  608. new Item(),
  609. new Item(),
  610. new Item(),
  611. };
  612. var vm = new MasterViewModel
  613. {
  614. Child = new ChildViewModel
  615. {
  616. Items = items,
  617. SelectedIndex = 1,
  618. }
  619. };
  620. var target = new SelectingItemsControl { DataContext = vm };
  621. var itemsBinding = new Binding("Child.Items");
  622. var selectedIndBinding = new Binding("Child.SelectedIndex");
  623. target.Bind(SelectingItemsControl.ItemsProperty, itemsBinding);
  624. target.Bind(SelectingItemsControl.SelectedIndexProperty, selectedIndBinding);
  625. Assert.Equal(1, target.SelectedIndex);
  626. target.SelectedIndex = 2;
  627. Assert.Equal(2, target.SelectedIndex);
  628. Assert.Equal(2, vm.Child.SelectedIndex);
  629. }
  630. [Fact]
  631. public void Should_Select_Correct_Item_When_Duplicate_Items_Are_Present()
  632. {
  633. var target = new ListBox
  634. {
  635. Template = Template(),
  636. Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz"},
  637. };
  638. target.ApplyTemplate();
  639. target.Presenter.ApplyTemplate();
  640. _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
  641. Assert.Equal(3, target.SelectedIndex);
  642. }
  643. [Fact]
  644. public void Should_Apply_Selected_Pseudoclass_To_Correct_Item_When_Duplicate_Items_Are_Present()
  645. {
  646. var target = new ListBox
  647. {
  648. Template = Template(),
  649. Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
  650. };
  651. target.ApplyTemplate();
  652. target.Presenter.ApplyTemplate();
  653. _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
  654. Assert.Equal(new[] { ":selected" }, target.Presenter.Panel.Children[3].Classes);
  655. }
  656. [Fact]
  657. public void Adding_Item_Before_SelectedItem_Should_Update_SelectedIndex()
  658. {
  659. var items = new ObservableCollection<string>
  660. {
  661. "Foo",
  662. "Bar",
  663. "Baz"
  664. };
  665. var target = new ListBox
  666. {
  667. Template = Template(),
  668. Items = items,
  669. SelectedIndex = 1,
  670. };
  671. target.ApplyTemplate();
  672. target.Presenter.ApplyTemplate();
  673. items.Insert(0, "Qux");
  674. Assert.Equal(2, target.SelectedIndex);
  675. Assert.Equal("Bar", target.SelectedItem);
  676. }
  677. [Fact]
  678. public void Removing_Item_Before_SelectedItem_Should_Update_SelectedIndex()
  679. {
  680. var items = new ObservableCollection<string>
  681. {
  682. "Foo",
  683. "Bar",
  684. "Baz"
  685. };
  686. var target = new ListBox
  687. {
  688. Template = Template(),
  689. Items = items,
  690. SelectedIndex = 1,
  691. };
  692. target.ApplyTemplate();
  693. target.Presenter.ApplyTemplate();
  694. items.RemoveAt(0);
  695. Assert.Equal(0, target.SelectedIndex);
  696. Assert.Equal("Bar", target.SelectedItem);
  697. }
  698. [Fact]
  699. public void Replacing_Selected_Item_Should_Update_SelectedItem()
  700. {
  701. var items = new ObservableCollection<string>
  702. {
  703. "Foo",
  704. "Bar",
  705. "Baz"
  706. };
  707. var target = new ListBox
  708. {
  709. Template = Template(),
  710. Items = items,
  711. SelectedIndex = 1,
  712. };
  713. target.ApplyTemplate();
  714. target.Presenter.ApplyTemplate();
  715. items[1] = "Qux";
  716. Assert.Equal(1, target.SelectedIndex);
  717. Assert.Equal("Qux", target.SelectedItem);
  718. }
  719. private FuncControlTemplate Template()
  720. {
  721. return new FuncControlTemplate<SelectingItemsControl>((control, scope) =>
  722. new ItemsPresenter
  723. {
  724. Name = "itemsPresenter",
  725. [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty],
  726. [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty],
  727. }.RegisterInNameScope(scope).WithNameScope(scope));
  728. }
  729. private class Item : Control, ISelectable
  730. {
  731. public string Value { get; set; }
  732. public bool IsSelected { get; set; }
  733. }
  734. private class MasterViewModel : NotifyingBase
  735. {
  736. private ChildViewModel _child;
  737. public ChildViewModel Child
  738. {
  739. get { return _child; }
  740. set
  741. {
  742. _child = value;
  743. RaisePropertyChanged();
  744. }
  745. }
  746. }
  747. private class ChildViewModel : NotifyingBase
  748. {
  749. public IList<Item> Items { get; set; }
  750. public Item SelectedItem { get; set; }
  751. public int SelectedIndex { get; set; }
  752. }
  753. private class RootWithItems : TestRoot
  754. {
  755. public List<string> Items { get; set; } = new List<string>() { "a", "b", "c", "d", "e" };
  756. public string Selected { get; set; } = "b";
  757. }
  758. }
  759. }