SelectingItemsControlTests.cs 37 KB

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