SelectingItemsControlTests.cs 33 KB

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