SelectingItemsControlTests.cs 30 KB

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