SelectingItemsControlTests.cs 51 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Collections.Specialized;
  5. using System.ComponentModel;
  6. using System.Linq;
  7. using Avalonia.Collections;
  8. using Avalonia.Controls.Presenters;
  9. using Avalonia.Controls.Primitives;
  10. using Avalonia.Controls.Selection;
  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.Styling;
  17. using Avalonia.UnitTests;
  18. using Moq;
  19. using Xunit;
  20. namespace Avalonia.Controls.UnitTests.Primitives
  21. {
  22. public partial class SelectingItemsControlTests
  23. {
  24. private MouseTestHelper _helper = new MouseTestHelper();
  25. [Fact]
  26. public void SelectedIndex_Should_Initially_Be_Minus_1()
  27. {
  28. var items = new[]
  29. {
  30. new Item(),
  31. new Item(),
  32. };
  33. var target = new SelectingItemsControl
  34. {
  35. Items = items,
  36. Template = Template(),
  37. };
  38. Assert.Equal(-1, target.SelectedIndex);
  39. }
  40. [Fact]
  41. public void Item_IsSelected_Should_Initially_Be_False()
  42. {
  43. var items = new[]
  44. {
  45. new Item(),
  46. new Item(),
  47. };
  48. var target = new SelectingItemsControl
  49. {
  50. Items = items,
  51. Template = Template(),
  52. };
  53. Prepare(target);
  54. Assert.False(items[0].IsSelected);
  55. Assert.False(items[1].IsSelected);
  56. }
  57. [Fact]
  58. public void Setting_SelectedItem_Should_Set_Item_IsSelected_True()
  59. {
  60. var items = new[]
  61. {
  62. new Item(),
  63. new Item(),
  64. };
  65. var target = new SelectingItemsControl
  66. {
  67. Items = items,
  68. Template = Template(),
  69. };
  70. Prepare(target);
  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. Prepare(target);
  90. Assert.False(items[0].IsSelected);
  91. Assert.True(items[1].IsSelected);
  92. }
  93. [Fact]
  94. public void SelectedIndex_Should_Be_Minus_1_After_Initialize()
  95. {
  96. var items = new[]
  97. {
  98. new Item(),
  99. new Item(),
  100. };
  101. var target = new ListBox();
  102. target.BeginInit();
  103. target.Items = items;
  104. target.Template = Template();
  105. target.EndInit();
  106. Assert.Equal(-1, target.SelectedIndex);
  107. }
  108. [Fact]
  109. public void SelectedIndex_Should_Be_Minus_1_Without_Initialize()
  110. {
  111. var items = new[]
  112. {
  113. new Item(),
  114. new Item(),
  115. };
  116. var target = new ListBox();
  117. target.Items = items;
  118. target.Template = Template();
  119. target.DataContext = new object();
  120. Assert.Equal(-1, target.SelectedIndex);
  121. }
  122. [Fact]
  123. public void SelectedIndex_Should_Be_0_After_Initialize_With_AlwaysSelected()
  124. {
  125. var items = new[]
  126. {
  127. new Item(),
  128. new Item(),
  129. };
  130. var target = new ListBox();
  131. target.BeginInit();
  132. target.SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected;
  133. target.Items = items;
  134. target.Template = Template();
  135. target.EndInit();
  136. Prepare(target);
  137. Assert.Equal(0, target.SelectedIndex);
  138. }
  139. [Fact]
  140. public void Setting_SelectedIndex_During_Initialize_Should_Select_Item_When_AlwaysSelected_Is_Used()
  141. {
  142. var listBox = new ListBox
  143. {
  144. SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected
  145. };
  146. listBox.BeginInit();
  147. listBox.SelectedIndex = 1;
  148. var items = new AvaloniaList<string>();
  149. listBox.Items = items;
  150. items.Add("A");
  151. items.Add("B");
  152. items.Add("C");
  153. listBox.EndInit();
  154. Prepare(listBox);
  155. Assert.Equal("B", listBox.SelectedItem);
  156. }
  157. [Fact]
  158. public void Setting_SelectedIndex_Before_Initialize_Should_Retain_Selection()
  159. {
  160. var listBox = new ListBox
  161. {
  162. SelectionMode = SelectionMode.Single,
  163. Items = new[] { "foo", "bar", "baz" },
  164. SelectedIndex = 1
  165. };
  166. listBox.BeginInit();
  167. listBox.EndInit();
  168. Assert.Equal(1, listBox.SelectedIndex);
  169. Assert.Equal("bar", listBox.SelectedItem);
  170. }
  171. [Fact]
  172. public void Setting_SelectedIndex_During_Initialize_Should_Take_Priority_Over_Previous_Value()
  173. {
  174. var listBox = new ListBox
  175. {
  176. SelectionMode = SelectionMode.Single,
  177. Items = new[] { "foo", "bar", "baz" },
  178. SelectedIndex = 2
  179. };
  180. listBox.BeginInit();
  181. listBox.SelectedIndex = 1;
  182. listBox.EndInit();
  183. Assert.Equal(1, listBox.SelectedIndex);
  184. Assert.Equal("bar", listBox.SelectedItem);
  185. }
  186. [Fact]
  187. public void Setting_SelectedItem_Before_Initialize_Should_Retain_Selection()
  188. {
  189. var listBox = new ListBox
  190. {
  191. SelectionMode = SelectionMode.Single,
  192. Items = new[] { "foo", "bar", "baz" },
  193. SelectedItem = "bar"
  194. };
  195. listBox.BeginInit();
  196. listBox.EndInit();
  197. Assert.Equal(1, listBox.SelectedIndex);
  198. Assert.Equal("bar", listBox.SelectedItem);
  199. }
  200. [Fact]
  201. public void Setting_SelectedItems_Before_Initialize_Should_Retain_Selection()
  202. {
  203. var listBox = new ListBox
  204. {
  205. SelectionMode = SelectionMode.Multiple,
  206. Items = new[] { "foo", "bar", "baz" },
  207. };
  208. var selected = new[] { "foo", "bar" };
  209. foreach (var v in selected)
  210. {
  211. listBox.SelectedItems.Add(v);
  212. }
  213. listBox.BeginInit();
  214. listBox.EndInit();
  215. Assert.Equal(selected, listBox.SelectedItems);
  216. }
  217. [Fact]
  218. public void Setting_SelectedItems_During_Initialize_Should_Take_Priority_Over_Previous_Value()
  219. {
  220. var listBox = new ListBox
  221. {
  222. SelectionMode = SelectionMode.Multiple,
  223. Items = new[] { "foo", "bar", "baz" },
  224. };
  225. var selected = new[] { "foo", "bar" };
  226. foreach (var v in new[] { "bar", "baz" })
  227. {
  228. listBox.SelectedItems.Add(v);
  229. }
  230. listBox.BeginInit();
  231. listBox.SelectedItems = new AvaloniaList<object>(selected);
  232. listBox.EndInit();
  233. Assert.Equal(selected, listBox.SelectedItems);
  234. }
  235. [Fact]
  236. public void Setting_SelectedIndex_Before_Initialize_With_AlwaysSelected_Should_Retain_Selection()
  237. {
  238. var listBox = new ListBox
  239. {
  240. SelectionMode = SelectionMode.Single | SelectionMode.AlwaysSelected,
  241. Items = new[] { "foo", "bar", "baz" },
  242. SelectedIndex = 1
  243. };
  244. listBox.BeginInit();
  245. listBox.EndInit();
  246. Assert.Equal(1, listBox.SelectedIndex);
  247. Assert.Equal("bar", listBox.SelectedItem);
  248. }
  249. [Fact]
  250. public void Setting_SelectedIndex_Before_ApplyTemplate_Should_Set_Item_IsSelected_True()
  251. {
  252. var items = new[]
  253. {
  254. new Item(),
  255. new Item(),
  256. };
  257. var target = new SelectingItemsControl
  258. {
  259. Items = items,
  260. Template = Template(),
  261. };
  262. target.SelectedIndex = 1;
  263. Prepare(target);
  264. Assert.False(items[0].IsSelected);
  265. Assert.True(items[1].IsSelected);
  266. }
  267. [Fact]
  268. public void Setting_SelectedItem_Should_Set_SelectedIndex()
  269. {
  270. var items = new[]
  271. {
  272. new Item(),
  273. new Item(),
  274. };
  275. var target = new SelectingItemsControl
  276. {
  277. Items = items,
  278. Template = Template(),
  279. };
  280. target.ApplyTemplate();
  281. target.SelectedItem = items[1];
  282. Assert.Equal(items[1], target.SelectedItem);
  283. Assert.Equal(1, target.SelectedIndex);
  284. }
  285. [Fact]
  286. public void SelectedIndex_Item_Is_Updated_As_Items_Removed_When_Last_Item_Is_Selected()
  287. {
  288. var items = new ObservableCollection<string>
  289. {
  290. "Foo",
  291. "Bar",
  292. "FooBar"
  293. };
  294. var target = new SelectingItemsControl
  295. {
  296. Items = items,
  297. Template = Template(),
  298. };
  299. target.ApplyTemplate();
  300. target.SelectedItem = items[2];
  301. Assert.Equal(items[2], target.SelectedItem);
  302. Assert.Equal(2, target.SelectedIndex);
  303. items.RemoveAt(0);
  304. Assert.Equal(items[1], target.SelectedItem);
  305. Assert.Equal(1, target.SelectedIndex);
  306. }
  307. [Fact]
  308. public void Setting_SelectedItem_To_Not_Present_Item_Should_Clear_Selection()
  309. {
  310. var items = new[]
  311. {
  312. new Item(),
  313. new Item(),
  314. };
  315. var target = new SelectingItemsControl
  316. {
  317. Items = items,
  318. Template = Template(),
  319. };
  320. target.ApplyTemplate();
  321. target.SelectedItem = items[1];
  322. Assert.Equal(items[1], target.SelectedItem);
  323. Assert.Equal(1, target.SelectedIndex);
  324. target.SelectedItem = new Item();
  325. Assert.Null(target.SelectedItem);
  326. Assert.Equal(-1, target.SelectedIndex);
  327. }
  328. [Fact]
  329. public void Setting_SelectedIndex_Should_Set_SelectedItem()
  330. {
  331. var items = new[]
  332. {
  333. new Item(),
  334. new Item(),
  335. };
  336. var target = new SelectingItemsControl
  337. {
  338. Items = items,
  339. Template = Template(),
  340. };
  341. target.ApplyTemplate();
  342. target.SelectedIndex = 1;
  343. Assert.Equal(items[1], target.SelectedItem);
  344. }
  345. [Fact]
  346. public void Setting_SelectedIndex_Out_Of_Bounds_Should_Clear_Selection()
  347. {
  348. var items = new[]
  349. {
  350. new Item(),
  351. new Item(),
  352. };
  353. var target = new SelectingItemsControl
  354. {
  355. Items = items,
  356. Template = Template(),
  357. };
  358. target.ApplyTemplate();
  359. target.SelectedIndex = 2;
  360. Assert.Equal(-1, target.SelectedIndex);
  361. }
  362. [Fact]
  363. public void Setting_SelectedItem_To_Non_Existent_Item_Should_Clear_Selection()
  364. {
  365. var target = new SelectingItemsControl
  366. {
  367. Template = Template(),
  368. };
  369. target.ApplyTemplate();
  370. target.SelectedItem = new Item();
  371. Assert.Equal(-1, target.SelectedIndex);
  372. Assert.Null(target.SelectedItem);
  373. }
  374. [Fact]
  375. public void Adding_Selected_Item_Should_Update_Selection()
  376. {
  377. var items = new AvaloniaList<Item>(new[]
  378. {
  379. new Item(),
  380. new Item(),
  381. });
  382. var target = new SelectingItemsControl
  383. {
  384. Items = items,
  385. Template = Template(),
  386. };
  387. Prepare(target);
  388. items.Add(new Item { IsSelected = true });
  389. Assert.Equal(2, target.SelectedIndex);
  390. Assert.Equal(items[2], target.SelectedItem);
  391. }
  392. [Fact]
  393. public void Setting_Items_To_Null_Should_Clear_Selection()
  394. {
  395. var items = new AvaloniaList<Item>
  396. {
  397. new Item(),
  398. new Item(),
  399. };
  400. var target = new SelectingItemsControl
  401. {
  402. Items = items,
  403. Template = Template(),
  404. };
  405. target.ApplyTemplate();
  406. target.SelectedIndex = 1;
  407. Assert.Equal(items[1], target.SelectedItem);
  408. Assert.Equal(1, target.SelectedIndex);
  409. target.Items = null;
  410. Assert.Null(target.SelectedItem);
  411. Assert.Equal(-1, target.SelectedIndex);
  412. }
  413. [Fact]
  414. public void Removing_Selected_Item_Should_Clear_Selection()
  415. {
  416. var items = new AvaloniaList<Item>
  417. {
  418. new Item(),
  419. new Item(),
  420. };
  421. var target = new SelectingItemsControl
  422. {
  423. Items = items,
  424. Template = Template(),
  425. };
  426. Prepare(target);
  427. target.SelectedIndex = 1;
  428. Assert.Equal(items[1], target.SelectedItem);
  429. Assert.Equal(1, target.SelectedIndex);
  430. SelectionChangedEventArgs receivedArgs = null;
  431. target.SelectionChanged += (_, args) => receivedArgs = args;
  432. var removed = items[1];
  433. items.RemoveAt(1);
  434. Assert.Null(target.SelectedItem);
  435. Assert.Equal(-1, target.SelectedIndex);
  436. Assert.NotNull(receivedArgs);
  437. Assert.Empty(receivedArgs.AddedItems);
  438. Assert.Equal(new[] { removed }, receivedArgs.RemovedItems);
  439. Assert.False(items.Single().IsSelected);
  440. }
  441. [Fact]
  442. public void Removing_Selected_Item_Should_Update_Selection_With_AlwaysSelected()
  443. {
  444. var item0 = new Item();
  445. var item1 = new Item();
  446. var items = new AvaloniaList<Item>
  447. {
  448. item0,
  449. item1,
  450. };
  451. var target = new TestSelector
  452. {
  453. Items = items,
  454. Template = Template(),
  455. SelectionMode = SelectionMode.AlwaysSelected,
  456. };
  457. Prepare(target);
  458. target.SelectedIndex = 1;
  459. Assert.Equal(items[1], target.SelectedItem);
  460. Assert.Equal(1, target.SelectedIndex);
  461. SelectionChangedEventArgs receivedArgs = null;
  462. target.SelectionChanged += (_, args) => receivedArgs = args;
  463. items.RemoveAt(1);
  464. Assert.Same(item0, target.SelectedItem);
  465. Assert.Equal(0, target.SelectedIndex);
  466. Assert.NotNull(receivedArgs);
  467. Assert.Equal(new[] { item0 }, receivedArgs.AddedItems);
  468. Assert.Equal(new[] { item1 }, receivedArgs.RemovedItems);
  469. Assert.True(items.Single().IsSelected);
  470. }
  471. [Fact]
  472. public void Removing_Selected_Item_Should_Clear_Selection_With_BeginInit()
  473. {
  474. var items = new AvaloniaList<Item>
  475. {
  476. new Item(),
  477. new Item(),
  478. };
  479. var target = new SelectingItemsControl();
  480. target.BeginInit();
  481. target.Items = items;
  482. target.Template = Template();
  483. target.EndInit();
  484. Prepare(target);
  485. target.SelectedIndex = 0;
  486. Assert.Equal(items[0], target.SelectedItem);
  487. Assert.Equal(0, target.SelectedIndex);
  488. SelectionChangedEventArgs receivedArgs = null;
  489. target.SelectionChanged += (_, args) => receivedArgs = args;
  490. var removed = items[0];
  491. items.RemoveAt(0);
  492. Assert.Null(target.SelectedItem);
  493. Assert.Equal(-1, target.SelectedIndex);
  494. Assert.NotNull(receivedArgs);
  495. Assert.Empty(receivedArgs.AddedItems);
  496. Assert.Equal(new[] { removed }, receivedArgs.RemovedItems);
  497. Assert.False(items.Single().IsSelected);
  498. }
  499. [Fact]
  500. public void Resetting_Items_Collection_Should_Clear_Selection()
  501. {
  502. // Need to use ObservableCollection here as AvaloniaList signals a Clear as an
  503. // add + remove.
  504. var items = new ObservableCollection<Item>
  505. {
  506. new Item(),
  507. new Item(),
  508. };
  509. var target = new SelectingItemsControl
  510. {
  511. Items = items,
  512. Template = Template(),
  513. };
  514. target.ApplyTemplate();
  515. target.SelectedIndex = 1;
  516. Assert.Equal(items[1], target.SelectedItem);
  517. Assert.Equal(1, target.SelectedIndex);
  518. items.Clear();
  519. Assert.Null(target.SelectedItem);
  520. Assert.Equal(-1, target.SelectedIndex);
  521. }
  522. [Fact]
  523. public void Raising_IsSelectedChanged_On_Item_Should_Update_Selection()
  524. {
  525. var items = new[]
  526. {
  527. new Item(),
  528. new Item(),
  529. };
  530. var target = new SelectingItemsControl
  531. {
  532. Items = items,
  533. Template = Template(),
  534. };
  535. Prepare(target);
  536. target.SelectedItem = items[1];
  537. Assert.False(items[0].IsSelected);
  538. Assert.True(items[1].IsSelected);
  539. items[0].IsSelected = true;
  540. items[0].RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
  541. Assert.Equal(0, target.SelectedIndex);
  542. Assert.Equal(items[0], target.SelectedItem);
  543. Assert.True(items[0].IsSelected);
  544. Assert.False(items[1].IsSelected);
  545. }
  546. [Fact]
  547. public void Clearing_IsSelected_And_Raising_IsSelectedChanged_On_Item_Should_Update_Selection()
  548. {
  549. var items = new[]
  550. {
  551. new Item(),
  552. new Item(),
  553. };
  554. var target = new SelectingItemsControl
  555. {
  556. Items = items,
  557. Template = Template(),
  558. };
  559. Prepare(target);
  560. target.SelectedItem = items[1];
  561. Assert.False(items[0].IsSelected);
  562. Assert.True(items[1].IsSelected);
  563. items[1].IsSelected = false;
  564. items[1].RaiseEvent(new RoutedEventArgs(SelectingItemsControl.IsSelectedChangedEvent));
  565. Assert.Equal(-1, target.SelectedIndex);
  566. Assert.Null(target.SelectedItem);
  567. }
  568. [Fact]
  569. public void Raising_IsSelectedChanged_On_Someone_Elses_Item_Should_Not_Update_Selection()
  570. {
  571. var items = new[]
  572. {
  573. new Item(),
  574. new Item(),
  575. };
  576. var target = new SelectingItemsControl
  577. {
  578. Items = items,
  579. Template = Template(),
  580. };
  581. target.ApplyTemplate();
  582. target.SelectedItem = items[1];
  583. var notChild = new Item
  584. {
  585. IsSelected = true,
  586. };
  587. target.RaiseEvent(new RoutedEventArgs
  588. {
  589. RoutedEvent = SelectingItemsControl.IsSelectedChangedEvent,
  590. Source = notChild,
  591. });
  592. Assert.Equal(target.SelectedItem, items[1]);
  593. }
  594. [Fact]
  595. public void Setting_SelectedIndex_Should_Raise_SelectionChanged_Event()
  596. {
  597. var items = new[]
  598. {
  599. new Item(),
  600. new Item(),
  601. };
  602. var target = new SelectingItemsControl
  603. {
  604. Items = items,
  605. Template = Template(),
  606. };
  607. var called = false;
  608. target.SelectionChanged += (s, e) =>
  609. {
  610. Assert.Same(items[1], e.AddedItems.Cast<object>().Single());
  611. Assert.Empty(e.RemovedItems);
  612. called = true;
  613. };
  614. target.SelectedIndex = 1;
  615. Assert.True(called);
  616. }
  617. [Fact]
  618. public void Clearing_SelectedIndex_Should_Raise_SelectionChanged_Event()
  619. {
  620. var items = new[]
  621. {
  622. new Item(),
  623. new Item(),
  624. };
  625. var target = new SelectingItemsControl
  626. {
  627. Items = items,
  628. Template = Template(),
  629. SelectedIndex = 1,
  630. };
  631. Prepare(target);
  632. var called = false;
  633. target.SelectionChanged += (s, e) =>
  634. {
  635. Assert.Same(items[1], e.RemovedItems.Cast<object>().Single());
  636. Assert.Empty(e.AddedItems);
  637. called = true;
  638. };
  639. target.SelectedIndex = -1;
  640. Assert.True(called);
  641. }
  642. [Fact]
  643. public void Setting_SelectedIndex_Should_Raise_PropertyChanged_Events()
  644. {
  645. var items = new ObservableCollection<string> { "foo", "bar", "baz" };
  646. var target = new TestSelector
  647. {
  648. Items = items,
  649. Template = Template(),
  650. };
  651. var selectedIndexRaised = 0;
  652. var selectedItemRaised = 0;
  653. target.PropertyChanged += (s, e) =>
  654. {
  655. if (e.Property == SelectingItemsControl.SelectedIndexProperty)
  656. {
  657. Assert.Equal(-1, e.OldValue);
  658. Assert.Equal(1, e.NewValue);
  659. ++selectedIndexRaised;
  660. }
  661. else if (e.Property == SelectingItemsControl.SelectedItemProperty)
  662. {
  663. Assert.Null(e.OldValue);
  664. Assert.Equal("bar", e.NewValue);
  665. ++selectedItemRaised;
  666. }
  667. };
  668. target.SelectedIndex = 1;
  669. Assert.Equal(1, selectedIndexRaised);
  670. Assert.Equal(1, selectedItemRaised);
  671. }
  672. [Fact]
  673. public void Removing_Selected_Item_Should_Raise_PropertyChanged_Events()
  674. {
  675. var items = new ObservableCollection<string> { "foo", "bar", "baz" };
  676. var target = new TestSelector
  677. {
  678. Items = items,
  679. Template = Template(),
  680. };
  681. var selectedIndexRaised = 0;
  682. var selectedItemRaised = 0;
  683. target.SelectedIndex = 1;
  684. target.PropertyChanged += (s, e) =>
  685. {
  686. if (e.Property == SelectingItemsControl.SelectedIndexProperty)
  687. {
  688. Assert.Equal(1, e.OldValue);
  689. Assert.Equal(-1, e.NewValue);
  690. ++selectedIndexRaised;
  691. }
  692. else if (e.Property == SelectingItemsControl.SelectedItemProperty)
  693. {
  694. Assert.Equal("bar", e.OldValue);
  695. Assert.Null(e.NewValue);
  696. }
  697. };
  698. items.RemoveAt(1);
  699. Assert.Equal(1, selectedIndexRaised);
  700. Assert.Equal(0, selectedItemRaised);
  701. }
  702. [Fact]
  703. public void Removing_Selected_Item0_Should_Raise_PropertyChanged_Events_With_AlwaysSelected()
  704. {
  705. var items = new ObservableCollection<string> { "foo", "bar", "baz" };
  706. var target = new TestSelector
  707. {
  708. Items = items,
  709. Template = Template(),
  710. SelectionMode = SelectionMode.AlwaysSelected,
  711. };
  712. var selectedIndexRaised = 0;
  713. var selectedItemRaised = 0;
  714. target.SelectedIndex = 0;
  715. target.PropertyChanged += (s, e) =>
  716. {
  717. if (e.Property == SelectingItemsControl.SelectedIndexProperty)
  718. {
  719. ++selectedIndexRaised;
  720. }
  721. else if (e.Property == SelectingItemsControl.SelectedItemProperty)
  722. {
  723. Assert.Equal("foo", e.OldValue);
  724. Assert.Equal("bar", e.NewValue);
  725. ++selectedItemRaised;
  726. }
  727. };
  728. items.RemoveAt(0);
  729. Assert.Equal(0, selectedIndexRaised);
  730. Assert.Equal(1, selectedItemRaised);
  731. }
  732. [Fact]
  733. public void Removing_Selected_Item1_Should_Raise_PropertyChanged_Events_With_AlwaysSelected()
  734. {
  735. var items = new ObservableCollection<string> { "foo", "bar", "baz" };
  736. var target = new TestSelector
  737. {
  738. Items = items,
  739. Template = Template(),
  740. SelectionMode = SelectionMode.AlwaysSelected,
  741. };
  742. var selectedIndexRaised = 0;
  743. var selectedItemRaised = 0;
  744. target.SelectedIndex = 1;
  745. target.PropertyChanged += (s, e) =>
  746. {
  747. if (e.Property == SelectingItemsControl.SelectedIndexProperty)
  748. {
  749. Assert.Equal(1, e.OldValue);
  750. Assert.Equal(0, e.NewValue);
  751. ++selectedIndexRaised;
  752. }
  753. else if (e.Property == SelectingItemsControl.SelectedItemProperty)
  754. {
  755. Assert.Equal("bar", e.OldValue);
  756. Assert.Equal("foo", e.NewValue);
  757. }
  758. };
  759. items.RemoveAt(1);
  760. Assert.Equal(1, selectedIndexRaised);
  761. Assert.Equal(0, selectedItemRaised);
  762. }
  763. [Fact]
  764. public void Removing_Item_Before_Selection_Should_Raise_PropertyChanged_Events()
  765. {
  766. var items = new ObservableCollection<string> { "foo", "bar", "baz" };
  767. var target = new SelectingItemsControl
  768. {
  769. Items = items,
  770. Template = Template(),
  771. };
  772. var selectedIndexRaised = 0;
  773. var selectedItemRaised = 0;
  774. target.SelectedIndex = 1;
  775. target.PropertyChanged += (s, e) =>
  776. {
  777. if (e.Property == SelectingItemsControl.SelectedIndexProperty)
  778. {
  779. Assert.Equal(1, e.OldValue);
  780. Assert.Equal(0, e.NewValue);
  781. ++selectedIndexRaised;
  782. }
  783. else if (e.Property == SelectingItemsControl.SelectedItemProperty)
  784. {
  785. ++selectedItemRaised;
  786. }
  787. };
  788. items.RemoveAt(0);
  789. Assert.Equal(1, selectedIndexRaised);
  790. Assert.Equal(0, selectedItemRaised);
  791. }
  792. [Fact]
  793. public void Order_Of_Setting_Items_And_SelectedIndex_During_Initialization_Should_Not_Matter()
  794. {
  795. var items = new[] { "Foo", "Bar" };
  796. var target = new SelectingItemsControl();
  797. ((ISupportInitialize)target).BeginInit();
  798. target.SelectedIndex = 1;
  799. target.Items = items;
  800. ((ISupportInitialize)target).EndInit();
  801. Prepare(target);
  802. Assert.Equal(1, target.SelectedIndex);
  803. Assert.Equal("Bar", target.SelectedItem);
  804. }
  805. [Fact]
  806. public void Order_Of_Setting_Items_And_SelectedItem_During_Initialization_Should_Not_Matter()
  807. {
  808. var items = new[] { "Foo", "Bar" };
  809. var target = new SelectingItemsControl();
  810. ((ISupportInitialize)target).BeginInit();
  811. target.SelectedItem = "Bar";
  812. target.Items = items;
  813. ((ISupportInitialize)target).EndInit();
  814. Prepare(target);
  815. Assert.Equal(1, target.SelectedIndex);
  816. Assert.Equal("Bar", target.SelectedItem);
  817. }
  818. [Fact]
  819. public void Changing_DataContext_Should_Not_Clear_Nested_ViewModel_SelectedItem()
  820. {
  821. var items = new[]
  822. {
  823. new Item(),
  824. new Item(),
  825. };
  826. var vm = new MasterViewModel
  827. {
  828. Child = new ChildViewModel
  829. {
  830. Items = items,
  831. SelectedItem = items[1],
  832. }
  833. };
  834. var target = new SelectingItemsControl { DataContext = vm };
  835. var itemsBinding = new Binding("Child.Items");
  836. var selectedBinding = new Binding("Child.SelectedItem");
  837. target.Bind(SelectingItemsControl.ItemsProperty, itemsBinding);
  838. target.Bind(SelectingItemsControl.SelectedItemProperty, selectedBinding);
  839. Assert.Equal(1, target.SelectedIndex);
  840. Assert.Same(vm.Child.SelectedItem, target.SelectedItem);
  841. items = new[]
  842. {
  843. new Item { Value = "Item1" },
  844. new Item { Value = "Item2" },
  845. new Item { Value = "Item3" },
  846. };
  847. vm = new MasterViewModel
  848. {
  849. Child = new ChildViewModel
  850. {
  851. Items = items,
  852. SelectedItem = items[2],
  853. }
  854. };
  855. target.DataContext = vm;
  856. Assert.Equal(2, target.SelectedIndex);
  857. Assert.Same(vm.Child.SelectedItem, target.SelectedItem);
  858. }
  859. [Fact]
  860. public void Nested_ListBox_Does_Not_Change_Parent_SelectedIndex()
  861. {
  862. SelectingItemsControl nested;
  863. var root = new SelectingItemsControl
  864. {
  865. Template = Template(),
  866. Items = new IControl[]
  867. {
  868. new Border(),
  869. nested = new ListBox
  870. {
  871. Template = Template(),
  872. Items = new[] { "foo", "bar" },
  873. SelectedIndex = 1,
  874. }
  875. },
  876. SelectedIndex = 0,
  877. };
  878. root.ApplyTemplate();
  879. root.Presenter.ApplyTemplate();
  880. nested.ApplyTemplate();
  881. nested.Presenter.ApplyTemplate();
  882. Assert.Equal(0, root.SelectedIndex);
  883. Assert.Equal(1, nested.SelectedIndex);
  884. nested.SelectedIndex = 0;
  885. Assert.Equal(0, root.SelectedIndex);
  886. }
  887. [Fact]
  888. public void Setting_SelectedItem_With_Pointer_Should_Set_TabOnceActiveElement()
  889. {
  890. var target = new ListBox
  891. {
  892. Template = Template(),
  893. Items = new[] { "Foo", "Bar", "Baz " },
  894. };
  895. Prepare(target);
  896. _helper.Down((Interactive)target.Presenter.Panel.Children[1]);
  897. var panel = target.Presenter.Panel;
  898. Assert.Equal(
  899. KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel),
  900. panel.Children[1]);
  901. }
  902. [Fact]
  903. public void Removing_SelectedItem_Should_Clear_TabOnceActiveElement()
  904. {
  905. var items = new ObservableCollection<string>(new[] { "Foo", "Bar", "Baz " });
  906. var target = new ListBox
  907. {
  908. Template = Template(),
  909. Items = items,
  910. };
  911. Prepare(target);
  912. _helper.Down(target.Presenter.Panel.Children[1]);
  913. items.RemoveAt(1);
  914. var panel = target.Presenter.Panel;
  915. Assert.Null(KeyboardNavigation.GetTabOnceActiveElement((InputElement)panel));
  916. }
  917. [Fact]
  918. public void Resetting_Items_Collection_Should_Retain_Selection()
  919. {
  920. var itemsMock = new Mock<List<string>>();
  921. var itemsMockAsINCC = itemsMock.As<INotifyCollectionChanged>();
  922. itemsMock.Object.AddRange(new[] { "Foo", "Bar", "Baz" });
  923. var target = new SelectingItemsControl
  924. {
  925. Items = itemsMock.Object
  926. };
  927. target.SelectedIndex = 1;
  928. itemsMockAsINCC.Raise(e => e.CollectionChanged += null, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  929. Assert.True(target.SelectedIndex == 1);
  930. }
  931. [Fact]
  932. public void Binding_With_DelayedBinding_And_Initialization_Where_DataContext_Is_Root_Works()
  933. {
  934. // Test for #1932.
  935. var root = new RootWithItems();
  936. root.BeginInit();
  937. root.DataContext = root;
  938. var target = new ListBox();
  939. target.BeginInit();
  940. root.Child = target;
  941. DelayedBinding.Add(target, ItemsControl.ItemsProperty, new Binding(nameof(RootWithItems.Items)));
  942. DelayedBinding.Add(target, ListBox.SelectedItemProperty, new Binding(nameof(RootWithItems.Selected)));
  943. target.EndInit();
  944. root.EndInit();
  945. Assert.Equal("b", target.SelectedItem);
  946. }
  947. [Fact]
  948. public void Mode_For_SelectedIndex_Is_TwoWay_By_Default()
  949. {
  950. var items = new[]
  951. {
  952. new Item(),
  953. new Item(),
  954. new Item(),
  955. };
  956. var vm = new MasterViewModel
  957. {
  958. Child = new ChildViewModel
  959. {
  960. Items = items,
  961. SelectedIndex = 1,
  962. }
  963. };
  964. var target = new SelectingItemsControl { DataContext = vm };
  965. var itemsBinding = new Binding("Child.Items");
  966. var selectedIndBinding = new Binding("Child.SelectedIndex");
  967. target.Bind(SelectingItemsControl.ItemsProperty, itemsBinding);
  968. target.Bind(SelectingItemsControl.SelectedIndexProperty, selectedIndBinding);
  969. Assert.Equal(1, target.SelectedIndex);
  970. target.SelectedIndex = 2;
  971. Assert.Equal(2, target.SelectedIndex);
  972. Assert.Equal(2, vm.Child.SelectedIndex);
  973. }
  974. [Fact]
  975. public void Should_Select_Correct_Item_When_Duplicate_Items_Are_Present()
  976. {
  977. var target = new ListBox
  978. {
  979. Template = Template(),
  980. Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
  981. };
  982. Prepare(target);
  983. _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
  984. Assert.Equal(3, target.SelectedIndex);
  985. }
  986. [Fact]
  987. public void Should_Apply_Selected_Pseudoclass_To_Correct_Item_When_Duplicate_Items_Are_Present()
  988. {
  989. var target = new ListBox
  990. {
  991. Template = Template(),
  992. Items = new[] { "Foo", "Bar", "Baz", "Foo", "Bar", "Baz" },
  993. };
  994. Prepare(target);
  995. _helper.Down((Interactive)target.Presenter.Panel.Children[3]);
  996. Assert.Equal(new[] { ":pressed", ":selected" }, target.Presenter.Panel.Children[3].Classes);
  997. }
  998. [Fact]
  999. public void Adding_Item_Before_SelectedItem_Should_Update_SelectedIndex()
  1000. {
  1001. var items = new ObservableCollection<string>
  1002. {
  1003. "Foo",
  1004. "Bar",
  1005. "Baz"
  1006. };
  1007. var target = new ListBox
  1008. {
  1009. Template = Template(),
  1010. Items = items,
  1011. SelectedIndex = 1,
  1012. };
  1013. Prepare(target);
  1014. items.Insert(0, "Qux");
  1015. Assert.Equal(2, target.SelectedIndex);
  1016. Assert.Equal("Bar", target.SelectedItem);
  1017. }
  1018. [Fact]
  1019. public void Removing_Item_Before_SelectedItem_Should_Update_SelectedIndex()
  1020. {
  1021. var items = new ObservableCollection<string>
  1022. {
  1023. "Foo",
  1024. "Bar",
  1025. "Baz"
  1026. };
  1027. var target = new ListBox
  1028. {
  1029. Template = Template(),
  1030. Items = items,
  1031. SelectedIndex = 1,
  1032. };
  1033. Prepare(target);
  1034. items.RemoveAt(0);
  1035. Assert.Equal(0, target.SelectedIndex);
  1036. Assert.Equal("Bar", target.SelectedItem);
  1037. }
  1038. [Fact]
  1039. public void Binding_SelectedIndex_Selects_Correct_Item()
  1040. {
  1041. // Issue #4496 (part 2)
  1042. var items = new ObservableCollection<string>();
  1043. var other = new ListBox
  1044. {
  1045. Template = Template(),
  1046. Items = items,
  1047. SelectionMode = SelectionMode.AlwaysSelected,
  1048. };
  1049. var target = new ListBox
  1050. {
  1051. Template = Template(),
  1052. Items = items,
  1053. [!ListBox.SelectedIndexProperty] = other[!ListBox.SelectedIndexProperty],
  1054. };
  1055. Prepare(other);
  1056. Prepare(target);
  1057. items.Add("Foo");
  1058. Assert.Equal(0, other.SelectedIndex);
  1059. Assert.Equal(0, target.SelectedIndex);
  1060. }
  1061. [Fact]
  1062. public void Binding_SelectedItem_Selects_Correct_Item()
  1063. {
  1064. // Issue #4496 (part 2)
  1065. var items = new ObservableCollection<string>();
  1066. var other = new ListBox
  1067. {
  1068. Template = Template(),
  1069. Items = items,
  1070. SelectionMode = SelectionMode.AlwaysSelected,
  1071. };
  1072. var target = new ListBox
  1073. {
  1074. Template = Template(),
  1075. Items = items,
  1076. [!ListBox.SelectedItemProperty] = other[!ListBox.SelectedItemProperty],
  1077. };
  1078. Prepare(target);
  1079. other.ApplyTemplate();
  1080. other.Presenter.ApplyTemplate();
  1081. items.Add("Foo");
  1082. Assert.Equal(0, other.SelectedIndex);
  1083. Assert.Equal(0, target.SelectedIndex);
  1084. }
  1085. [Fact]
  1086. public void Replacing_Selected_Item_Should_Update_SelectedItem()
  1087. {
  1088. var items = new ObservableCollection<string>
  1089. {
  1090. "Foo",
  1091. "Bar",
  1092. "Baz"
  1093. };
  1094. var target = new ListBox
  1095. {
  1096. Template = Template(),
  1097. Items = items,
  1098. SelectedIndex = 1,
  1099. };
  1100. Prepare(target);
  1101. items[1] = "Qux";
  1102. Assert.Equal(-1, target.SelectedIndex);
  1103. Assert.Null(target.SelectedItem);
  1104. }
  1105. [Fact]
  1106. public void AutoScrollToSelectedItem_Causes_Scroll_To_SelectedItem()
  1107. {
  1108. var items = new ObservableCollection<string>
  1109. {
  1110. "Foo",
  1111. "Bar",
  1112. "Baz"
  1113. };
  1114. var target = new ListBox
  1115. {
  1116. Template = Template(),
  1117. Items = items,
  1118. };
  1119. Prepare(target);
  1120. var raised = false;
  1121. target.AddHandler(Control.RequestBringIntoViewEvent, (s, e) => raised = true);
  1122. target.SelectedIndex = 2;
  1123. Assert.True(raised);
  1124. }
  1125. [Fact]
  1126. public void AutoScrollToSelectedItem_On_Reset_Works()
  1127. {
  1128. // Issue #3148
  1129. using (UnitTestApplication.Start(TestServices.StyledWindow))
  1130. {
  1131. var items = new ResettingCollection(100);
  1132. var target = new ListBox
  1133. {
  1134. Items = items,
  1135. ItemTemplate = new FuncDataTemplate<string>((x, _) =>
  1136. new TextBlock
  1137. {
  1138. Text = x,
  1139. Width = 100,
  1140. Height = 10
  1141. }),
  1142. AutoScrollToSelectedItem = true,
  1143. VirtualizationMode = ItemVirtualizationMode.Simple,
  1144. };
  1145. var root = new TestRoot(true, target);
  1146. root.Measure(new Size(100, 100));
  1147. root.Arrange(new Rect(0, 0, 100, 100));
  1148. Assert.True(target.Presenter.Panel.Children.Count > 0);
  1149. Assert.True(target.Presenter.Panel.Children.Count < 100);
  1150. target.SelectedItem = "Item99";
  1151. // #3148 triggered here.
  1152. items.Reset(new[] { "Item99" });
  1153. Assert.Equal(0, target.SelectedIndex);
  1154. Assert.Equal(1, target.Presenter.Panel.Children.Count);
  1155. }
  1156. }
  1157. [Fact]
  1158. public void Can_Set_Both_SelectedItem_And_SelectedItems_During_Initialization()
  1159. {
  1160. // Issue #2969.
  1161. var target = new ListBox();
  1162. var selectedItems = new List<object>();
  1163. target.BeginInit();
  1164. target.Template = Template();
  1165. target.Items = new[] { "Foo", "Bar", "Baz" };
  1166. target.SelectedItems = selectedItems;
  1167. target.SelectedItem = "Bar";
  1168. target.EndInit();
  1169. Prepare(target);
  1170. Assert.Equal("Bar", target.SelectedItem);
  1171. Assert.Equal(1, target.SelectedIndex);
  1172. Assert.Same(selectedItems, target.SelectedItems);
  1173. Assert.Equal(new[] { "Bar" }, selectedItems);
  1174. }
  1175. [Fact]
  1176. public void MoveSelection_Wrap_Does_Not_Hang_With_No_Focusable_Controls()
  1177. {
  1178. // Issue #3094.
  1179. var target = new TestSelector
  1180. {
  1181. Template = Template(),
  1182. Items = new[]
  1183. {
  1184. new ListBoxItem { Focusable = false },
  1185. new ListBoxItem { Focusable = false },
  1186. },
  1187. SelectedIndex = 0,
  1188. };
  1189. target.Measure(new Size(100, 100));
  1190. target.Arrange(new Rect(0, 0, 100, 100));
  1191. target.MoveSelection(NavigationDirection.Next, true);
  1192. }
  1193. [Fact]
  1194. public void MoveSelection_Does_Select_Disabled_Controls()
  1195. {
  1196. // Issue #3426.
  1197. var target = new TestSelector
  1198. {
  1199. Template = Template(),
  1200. Items = new[]
  1201. {
  1202. new ListBoxItem(),
  1203. new ListBoxItem { IsEnabled = false },
  1204. },
  1205. SelectedIndex = 0,
  1206. };
  1207. target.Measure(new Size(100, 100));
  1208. target.Arrange(new Rect(0, 0, 100, 100));
  1209. target.MoveSelection(NavigationDirection.Next, true);
  1210. Assert.Equal(0, target.SelectedIndex);
  1211. }
  1212. [Fact]
  1213. public void Pre_Selecting_Item_Should_Set_Selection_After_It_Was_Added_When_AlwaysSelected()
  1214. {
  1215. var target = new TestSelector(SelectionMode.AlwaysSelected)
  1216. {
  1217. Template = Template()
  1218. };
  1219. var second = new Item { IsSelected = true };
  1220. var items = new AvaloniaList<object>
  1221. {
  1222. new Item(),
  1223. second
  1224. };
  1225. target.Items = items;
  1226. Prepare(target);
  1227. Assert.Equal(second, target.SelectedItem);
  1228. Assert.Equal(1, target.SelectedIndex);
  1229. }
  1230. [Fact]
  1231. public void Setting_SelectionMode_Should_Update_SelectionModel()
  1232. {
  1233. var target = new TestSelector();
  1234. var model = target.Selection;
  1235. Assert.True(model.SingleSelect);
  1236. target.SelectionMode = SelectionMode.Multiple;
  1237. Assert.False(model.SingleSelect);
  1238. }
  1239. [Fact]
  1240. public void Does_The_Best_It_Can_With_AutoSelecting_ViewModel()
  1241. {
  1242. // Tests the following scenario:
  1243. //
  1244. // - Items changes from empty to having 1 item
  1245. // - ViewModel auto-selects item 0 in CollectionChanged
  1246. // - SelectionModel receives CollectionChanged
  1247. // - And so adjusts the selected item from 0 to 1, which is past the end of the items.
  1248. //
  1249. // There's not much we can do about this situation because the order in which
  1250. // CollectionChanged handlers are called can't be known (the problem also exists with
  1251. // WPF). The best we can do is not select an invalid index.
  1252. var vm = new SelectionViewModel();
  1253. vm.Items.CollectionChanged += (s, e) =>
  1254. {
  1255. if (vm.SelectedIndex == -1 && vm.Items.Count > 0)
  1256. {
  1257. vm.SelectedIndex = 0;
  1258. }
  1259. };
  1260. var target = new ListBox
  1261. {
  1262. [!ListBox.ItemsProperty] = new Binding("Items"),
  1263. [!ListBox.SelectedIndexProperty] = new Binding("SelectedIndex"),
  1264. DataContext = vm,
  1265. };
  1266. Prepare(target);
  1267. vm.Items.Add("foo");
  1268. vm.Items.Add("bar");
  1269. Assert.Equal(0, target.SelectedIndex);
  1270. Assert.Equal(new[] { 0 }, target.Selection.SelectedIndexes);
  1271. Assert.Equal("foo", target.SelectedItem);
  1272. Assert.Equal(new[] { "foo" }, target.SelectedItems);
  1273. }
  1274. [Fact]
  1275. public void Preserves_Initial_SelectedItems_When_Bound()
  1276. {
  1277. // Issue #4272 (there are two issues there, this addresses the second one).
  1278. var vm = new SelectionViewModel
  1279. {
  1280. Items = { "foo", "bar", "baz" },
  1281. SelectedItems = { "bar" },
  1282. };
  1283. var target = new ListBox
  1284. {
  1285. [!ListBox.ItemsProperty] = new Binding("Items"),
  1286. [!ListBox.SelectedItemsProperty] = new Binding("SelectedItems"),
  1287. DataContext = vm,
  1288. };
  1289. Prepare(target);
  1290. Assert.Equal(1, target.SelectedIndex);
  1291. Assert.Equal(new[] { 1 }, target.Selection.SelectedIndexes);
  1292. Assert.Equal("bar", target.SelectedItem);
  1293. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  1294. }
  1295. [Fact]
  1296. public void Preserves_SelectedItem_When_Items_Changed()
  1297. {
  1298. // Issue #4048
  1299. var target = new SelectingItemsControl
  1300. {
  1301. Items = new[] { "foo", "bar", "baz"},
  1302. SelectedItem = "bar",
  1303. };
  1304. Prepare(target);
  1305. Assert.Equal(1, target.SelectedIndex);
  1306. Assert.Equal("bar", target.SelectedItem);
  1307. target.Items = new[] { "qux", "foo", "bar" };
  1308. Assert.Equal(2, target.SelectedIndex);
  1309. Assert.Equal("bar", target.SelectedItem);
  1310. }
  1311. private static void Prepare(SelectingItemsControl target)
  1312. {
  1313. var root = new TestRoot
  1314. {
  1315. Child = target,
  1316. Width = 100,
  1317. Height = 100,
  1318. Styles =
  1319. {
  1320. new Style(x => x.Is<SelectingItemsControl>())
  1321. {
  1322. Setters =
  1323. {
  1324. new Setter(ListBox.TemplateProperty, Template()),
  1325. },
  1326. },
  1327. },
  1328. };
  1329. root.LayoutManager.ExecuteInitialLayoutPass();
  1330. }
  1331. private static FuncControlTemplate Template()
  1332. {
  1333. return new FuncControlTemplate<SelectingItemsControl>((control, scope) =>
  1334. new ItemsPresenter
  1335. {
  1336. Name = "itemsPresenter",
  1337. [~ItemsPresenter.ItemsProperty] = control[~ItemsControl.ItemsProperty],
  1338. [~ItemsPresenter.ItemsPanelProperty] = control[~ItemsControl.ItemsPanelProperty],
  1339. [~ItemsPresenter.VirtualizationModeProperty] = control[~ListBox.VirtualizationModeProperty],
  1340. }.RegisterInNameScope(scope));
  1341. }
  1342. private class Item : Control, ISelectable
  1343. {
  1344. public string Value { get; set; }
  1345. public bool IsSelected { get; set; }
  1346. }
  1347. private class MasterViewModel : NotifyingBase
  1348. {
  1349. private ChildViewModel _child;
  1350. public ChildViewModel Child
  1351. {
  1352. get { return _child; }
  1353. set
  1354. {
  1355. _child = value;
  1356. RaisePropertyChanged();
  1357. }
  1358. }
  1359. }
  1360. private class ChildViewModel : NotifyingBase
  1361. {
  1362. public IList<Item> Items { get; set; }
  1363. public Item SelectedItem { get; set; }
  1364. public int SelectedIndex { get; set; }
  1365. }
  1366. private class SelectionViewModel : NotifyingBase
  1367. {
  1368. private int _selectedIndex = -1;
  1369. public SelectionViewModel()
  1370. {
  1371. Items = new ObservableCollection<string>();
  1372. SelectedItems = new ObservableCollection<string>();
  1373. }
  1374. public int SelectedIndex
  1375. {
  1376. get => _selectedIndex;
  1377. set
  1378. {
  1379. _selectedIndex = value;
  1380. RaisePropertyChanged();
  1381. }
  1382. }
  1383. public ObservableCollection<string> Items { get; }
  1384. public ObservableCollection<string> SelectedItems { get; }
  1385. }
  1386. private class RootWithItems : TestRoot
  1387. {
  1388. public List<string> Items { get; set; } = new List<string>() { "a", "b", "c", "d", "e" };
  1389. public string Selected { get; set; } = "b";
  1390. }
  1391. private class TestSelector : SelectingItemsControl
  1392. {
  1393. public TestSelector()
  1394. {
  1395. }
  1396. public TestSelector(SelectionMode selectionMode)
  1397. {
  1398. SelectionMode = selectionMode;
  1399. }
  1400. public new ISelectionModel Selection
  1401. {
  1402. get => base.Selection;
  1403. set => base.Selection = value;
  1404. }
  1405. public new SelectionMode SelectionMode
  1406. {
  1407. get => base.SelectionMode;
  1408. set => base.SelectionMode = value;
  1409. }
  1410. public new bool MoveSelection(NavigationDirection direction, bool wrap)
  1411. {
  1412. return base.MoveSelection(direction, wrap);
  1413. }
  1414. }
  1415. private class ResettingCollection : List<string>, INotifyCollectionChanged
  1416. {
  1417. public ResettingCollection(int itemCount)
  1418. {
  1419. AddRange(Enumerable.Range(0, itemCount).Select(x => $"Item{x}"));
  1420. }
  1421. public void Reset(IEnumerable<string> items)
  1422. {
  1423. Clear();
  1424. AddRange(items);
  1425. CollectionChanged?.Invoke(
  1426. this,
  1427. new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
  1428. }
  1429. public event NotifyCollectionChangedEventHandler CollectionChanged;
  1430. }
  1431. }
  1432. }