SelectionModelTests_Single.cs 38 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210
  1. using System;
  2. using System.Collections.Specialized;
  3. using Avalonia.Collections;
  4. using Avalonia.Controls.Selection;
  5. using Avalonia.Controls.Utils;
  6. using Xunit;
  7. using CollectionChangedEventManager = Avalonia.Controls.Utils.CollectionChangedEventManager;
  8. #nullable enable
  9. namespace Avalonia.Controls.UnitTests.Selection
  10. {
  11. public class SelectionModelTests_Single
  12. {
  13. public class Source
  14. {
  15. [Fact]
  16. public void Can_Select_Index_Before_Source_Assigned()
  17. {
  18. var target = CreateTarget(false);
  19. var raised = 0;
  20. target.SelectionChanged += (s, e) =>
  21. {
  22. Assert.Empty(e.DeselectedIndexes);
  23. Assert.Empty(e.DeselectedItems);
  24. Assert.Equal(new[] { 5 }, e.SelectedIndexes);
  25. Assert.Equal(new string?[] { null }, e.SelectedItems);
  26. ++raised;
  27. };
  28. target.SelectedIndex = 5;
  29. Assert.Equal(5, target.SelectedIndex);
  30. Assert.Equal(new[] { 5 }, target.SelectedIndexes);
  31. Assert.Null(target.SelectedItem);
  32. Assert.Equal(new string?[] { null }, target.SelectedItems);
  33. Assert.Equal(1, raised);
  34. }
  35. [Fact]
  36. public void Can_Select_Item_Before_Source_Assigned()
  37. {
  38. var target = CreateTarget(false);
  39. var raised = 0;
  40. target.SelectionChanged += (s, e) => ++raised;
  41. target.SelectedItem = "bar";
  42. Assert.Equal(-1, target.SelectedIndex);
  43. Assert.Empty(target.SelectedIndexes);
  44. Assert.Equal("bar", target.SelectedItem);
  45. Assert.Equal(new string?[] { "bar" }, target.SelectedItems);
  46. Assert.Equal(0, raised);
  47. }
  48. [Fact]
  49. public void Initializing_Source_Retains_Valid_Index_Selection()
  50. {
  51. var target = CreateTarget(false);
  52. var raised = 0;
  53. target.SelectedIndex = 1;
  54. target.SelectionChanged += (s, e) => ++raised;
  55. target.Source = new[] { "foo", "bar", "baz" };
  56. Assert.Equal(1, target.SelectedIndex);
  57. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  58. Assert.Equal("bar", target.SelectedItem);
  59. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  60. Assert.Equal(0, raised);
  61. }
  62. [Fact]
  63. public void Initializing_Source_Removes_Invalid_Index_Selection()
  64. {
  65. var target = CreateTarget(false);
  66. var raised = 0;
  67. target.SelectedIndex = 5;
  68. target.SelectionChanged += (s, e) =>
  69. {
  70. Assert.Equal(new[] { 5 }, e.DeselectedIndexes);
  71. Assert.Equal(new string?[] { null }, e.DeselectedItems);
  72. Assert.Empty(e.SelectedIndexes);
  73. Assert.Empty(e.SelectedItems);
  74. ++raised;
  75. };
  76. target.Source = new[] { "foo", "bar", "baz" };
  77. Assert.Equal(-1, target.SelectedIndex);
  78. Assert.Empty(target.SelectedIndexes);
  79. Assert.Null(target.SelectedItem);
  80. Assert.Empty(target.SelectedItems);
  81. Assert.Equal(1, raised);
  82. }
  83. [Fact]
  84. public void Initializing_Source_Retains_Valid_Item_Selection()
  85. {
  86. var target = CreateTarget(false);
  87. var raised = 0;
  88. target.SelectedItem = "bar";
  89. target.SelectionChanged += (s, e) =>
  90. {
  91. Assert.Empty(e.DeselectedIndexes);
  92. Assert.Empty(e.DeselectedItems);
  93. Assert.Equal(new[] { 1 }, e.SelectedIndexes);
  94. Assert.Equal(new string[] { "bar" }, e.SelectedItems);
  95. ++raised;
  96. };
  97. target.Source = new[] { "foo", "bar", "baz" };
  98. Assert.Equal(1, target.SelectedIndex);
  99. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  100. Assert.Equal("bar", target.SelectedItem);
  101. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  102. Assert.Equal(1, raised);
  103. }
  104. [Fact]
  105. public void Initializing_Source_Removes_Invalid_Item_Selection()
  106. {
  107. var target = CreateTarget(false);
  108. var raised = 0;
  109. target.SelectedItem = "qux";
  110. target.SelectionChanged += (s, e) => ++raised;
  111. target.Source = new[] { "foo", "bar", "baz" };
  112. Assert.Equal(-1, target.SelectedIndex);
  113. Assert.Empty(target.SelectedIndexes);
  114. Assert.Null(target.SelectedItem);
  115. Assert.Empty(target.SelectedItems);
  116. Assert.Equal(0, raised);
  117. }
  118. [Fact]
  119. public void Initializing_Source_Respects_SourceIndex_SourceItem_Order()
  120. {
  121. var target = CreateTarget(false);
  122. target.SelectedIndex = 0;
  123. target.SelectedItem = "bar";
  124. target.Source = new[] { "foo", "bar", "baz" };
  125. Assert.Equal(1, target.SelectedIndex);
  126. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  127. Assert.Equal("bar", target.SelectedItem);
  128. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  129. }
  130. [Fact]
  131. public void Initializing_Source_Respects_SourceItem_SourceIndex_Order()
  132. {
  133. var target = CreateTarget(false);
  134. target.SelectedItem = "foo";
  135. target.SelectedIndex = 1;
  136. target.Source = new[] { "foo", "bar", "baz" };
  137. Assert.Equal(1, target.SelectedIndex);
  138. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  139. Assert.Equal("bar", target.SelectedItem);
  140. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  141. }
  142. [Fact]
  143. public void Changing_Source_To_Null_Doesnt_Clear_Selection()
  144. {
  145. var target = CreateTarget();
  146. var raised = 0;
  147. target.SelectedIndex = 2;
  148. target.SelectionChanged += (s, e) => ++raised;
  149. target.Source = null;
  150. Assert.Equal(2, target.SelectedIndex);
  151. Assert.Equal(new[] { 2 }, target.SelectedIndexes);
  152. Assert.Null(target.SelectedItem);
  153. Assert.Equal(new string?[] { null }, target.SelectedItems);
  154. Assert.Equal(0, raised);
  155. }
  156. [Fact]
  157. public void Changing_Source_To_NonNUll_First_Clears_Old_Selection()
  158. {
  159. var target = CreateTarget();
  160. var raised = 0;
  161. target.SelectedIndex = 2;
  162. target.SelectionChanged += (s, e) =>
  163. {
  164. Assert.Equal(new[] { 2 }, e.DeselectedIndexes);
  165. Assert.Equal(new string?[] { "baz" }, e.DeselectedItems);
  166. Assert.Empty(e.SelectedIndexes);
  167. Assert.Empty(e.SelectedItems);
  168. ++raised;
  169. };
  170. target.Source = new[] { "qux", "quux", "corge" };
  171. Assert.Equal(-1, target.SelectedIndex);
  172. Assert.Empty(target.SelectedIndexes);
  173. Assert.Null(target.SelectedItem);
  174. Assert.Empty(target.SelectedItems);
  175. Assert.Equal(1, raised);
  176. }
  177. [Fact]
  178. public void Raises_PropertyChanged()
  179. {
  180. var target = CreateTarget();
  181. var raised = 0;
  182. target.PropertyChanged += (s, e) =>
  183. {
  184. if (e.PropertyName == nameof(target.Source))
  185. {
  186. ++raised;
  187. }
  188. };
  189. target.Source = new[] { "qux", "quux", "corge" };
  190. Assert.Equal(1, raised);
  191. }
  192. [Fact]
  193. public void Can_Assign_ValueType_Collection_To_SelectionModel_Of_Object()
  194. {
  195. var target = (ISelectionModel)new SelectionModel<object>();
  196. target.Source = new[] { 1, 2, 3 };
  197. }
  198. }
  199. public class SelectedIndex
  200. {
  201. [Fact]
  202. public void SelectedIndex_Larger_Than_Source_Clears_Selection()
  203. {
  204. var target = CreateTarget();
  205. var raised = 0;
  206. target.SelectedIndex = 1;
  207. target.SelectionChanged += (s, e) =>
  208. {
  209. Assert.Equal(new[] { 1 }, e.DeselectedIndexes);
  210. Assert.Equal(new[] { "bar" }, e.DeselectedItems);
  211. Assert.Empty(e.SelectedIndexes);
  212. Assert.Empty(e.SelectedItems);
  213. ++raised;
  214. };
  215. target.SelectedIndex = 5;
  216. Assert.Equal(-1, target.SelectedIndex);
  217. Assert.Empty(target.SelectedIndexes);
  218. Assert.Null(target.SelectedItem);
  219. Assert.Empty(target.SelectedItems);
  220. Assert.Equal(1, raised);
  221. }
  222. [Fact]
  223. public void Negative_SelectedIndex_Is_Coerced_To_Minus_1()
  224. {
  225. var target = CreateTarget();
  226. var raised = 0;
  227. target.SelectionChanged += (s, e) => ++raised;
  228. target.SelectedIndex = -5;
  229. Assert.Equal(-1, target.SelectedIndex);
  230. Assert.Empty(target.SelectedIndexes);
  231. Assert.Null(target.SelectedItem);
  232. Assert.Empty(target.SelectedItems);
  233. Assert.Equal(0, raised);
  234. }
  235. [Fact]
  236. public void Setting_SelectedIndex_Clears_Old_Selection()
  237. {
  238. var target = CreateTarget();
  239. var raised = 0;
  240. target.SelectedIndex = 0;
  241. target.SelectionChanged += (s, e) =>
  242. {
  243. Assert.Equal(new[] { 0 }, e.DeselectedIndexes);
  244. Assert.Equal(new[] { "foo" }, e.DeselectedItems);
  245. Assert.Equal(new[] { 1 }, e.SelectedIndexes);
  246. Assert.Equal(new[] { "bar" }, e.SelectedItems);
  247. ++raised;
  248. };
  249. target.SelectedIndex = 1;
  250. Assert.Equal(1, target.SelectedIndex);
  251. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  252. Assert.Equal("bar", target.SelectedItem);
  253. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  254. Assert.Equal(1, raised);
  255. }
  256. [Fact]
  257. public void Setting_SelectedIndex_During_CollectionChanged_Results_In_Correct_Selection()
  258. {
  259. // Issue #4496
  260. var data = new AvaloniaList<string>();
  261. var target = CreateTarget();
  262. var binding = new MockBinding(target, data);
  263. target.Source = data;
  264. data.Add("foo");
  265. Assert.Equal(0, target.SelectedIndex);
  266. }
  267. [Fact]
  268. public void PropertyChanged_Is_Raised()
  269. {
  270. var target = CreateTarget();
  271. var raised = 0;
  272. target.PropertyChanged += (s, e) =>
  273. {
  274. if (e.PropertyName == nameof(target.SelectedIndex))
  275. {
  276. ++raised;
  277. }
  278. };
  279. target.SelectedIndex = 1;
  280. Assert.Equal(1, raised);
  281. }
  282. private class MockBinding : ICollectionChangedListener
  283. {
  284. private readonly SelectionModel<string?> _target;
  285. public MockBinding(SelectionModel<string?> target, AvaloniaList<string> data)
  286. {
  287. _target = target;
  288. CollectionChangedEventManager.Instance.AddListener(data, this);
  289. }
  290. public void Changed(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e)
  291. {
  292. _target.Select(0);
  293. }
  294. public void PostChanged(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e)
  295. {
  296. }
  297. public void PreChanged(INotifyCollectionChanged sender, NotifyCollectionChangedEventArgs e)
  298. {
  299. }
  300. }
  301. }
  302. public class SelectedItem
  303. {
  304. [Fact]
  305. public void Setting_SelectedItem_To_Valid_Item_Updates_Selection()
  306. {
  307. var target = CreateTarget();
  308. var raised = 0;
  309. target.SelectionChanged += (s, e) =>
  310. {
  311. Assert.Empty(e.DeselectedIndexes);
  312. Assert.Empty(e.DeselectedItems);
  313. Assert.Equal(new[] { 1 }, e.SelectedIndexes);
  314. Assert.Equal(new[] { "bar" }, e.SelectedItems);
  315. ++raised;
  316. };
  317. target.SelectedItem = "bar";
  318. Assert.Equal(1, raised);
  319. }
  320. [Fact]
  321. public void PropertyChanged_Is_Raised_When_SelectedIndex_Changes()
  322. {
  323. var target = CreateTarget();
  324. var raised = 0;
  325. target.PropertyChanged += (s, e) =>
  326. {
  327. if (e.PropertyName == nameof(target.SelectedItem))
  328. {
  329. ++raised;
  330. }
  331. };
  332. target.SelectedIndex = 1;
  333. Assert.Equal(1, raised);
  334. }
  335. }
  336. public class SelectedIndexes
  337. {
  338. [Fact]
  339. public void PropertyChanged_Is_Raised_When_SelectedIndex_Changes()
  340. {
  341. var target = CreateTarget();
  342. var raised = 0;
  343. target.PropertyChanged += (s, e) =>
  344. {
  345. if (e.PropertyName == nameof(target.SelectedIndexes))
  346. {
  347. ++raised;
  348. }
  349. };
  350. target.SelectedIndex = 1;
  351. Assert.Equal(1, raised);
  352. }
  353. }
  354. public class SelectedItems
  355. {
  356. [Fact]
  357. public void PropertyChanged_Is_Raised_When_SelectedIndex_Changes()
  358. {
  359. var target = CreateTarget();
  360. var raised = 0;
  361. target.PropertyChanged += (s, e) =>
  362. {
  363. if (e.PropertyName == nameof(target.SelectedItems))
  364. {
  365. ++raised;
  366. }
  367. };
  368. target.SelectedIndex = 1;
  369. Assert.Equal(1, raised);
  370. }
  371. }
  372. public class Select
  373. {
  374. [Fact]
  375. public void Select_Sets_SelectedIndex()
  376. {
  377. var target = CreateTarget();
  378. var raised = 0;
  379. target.SelectedIndex = 0;
  380. target.PropertyChanged += (s, e) =>
  381. {
  382. if (e.PropertyName == nameof(target.SelectedIndex))
  383. {
  384. ++raised;
  385. }
  386. };
  387. target.Select(1);
  388. Assert.Equal(1, target.SelectedIndex);
  389. Assert.Equal(1, raised);
  390. }
  391. [Fact]
  392. public void Select_Clears_Old_Selection()
  393. {
  394. var target = CreateTarget();
  395. var raised = 0;
  396. target.SelectedIndex = 0;
  397. target.SelectionChanged += (s, e) =>
  398. {
  399. Assert.Equal(new[] { 0 }, e.DeselectedIndexes);
  400. Assert.Equal(new[] { "foo" }, e.DeselectedItems);
  401. Assert.Equal(new[] { 1 }, e.SelectedIndexes);
  402. Assert.Equal(new[] { "bar" }, e.SelectedItems);
  403. ++raised;
  404. };
  405. target.Select(1);
  406. Assert.Equal(1, target.SelectedIndex);
  407. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  408. Assert.Equal("bar", target.SelectedItem);
  409. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  410. Assert.Equal(1, raised);
  411. }
  412. [Fact]
  413. public void Select_With_Invalid_Index_Does_Nothing()
  414. {
  415. var target = CreateTarget();
  416. var raised = 0;
  417. target.SelectedIndex = 0;
  418. target.PropertyChanged += (s, e) => ++raised;
  419. target.SelectionChanged += (s, e) => ++raised;
  420. target.Select(5);
  421. Assert.Equal(0, target.SelectedIndex);
  422. Assert.Equal(new[] { 0 }, target.SelectedIndexes);
  423. Assert.Equal("foo", target.SelectedItem);
  424. Assert.Equal(new[] { "foo" }, target.SelectedItems);
  425. Assert.Equal(0, raised);
  426. }
  427. [Fact]
  428. public void Selecting_Already_Selected_Item_Doesnt_Raise_SelectionChanged()
  429. {
  430. var target = CreateTarget();
  431. var raised = 0;
  432. target.Select(2);
  433. target.SelectionChanged += (s, e) => ++raised;
  434. target.Select(2);
  435. Assert.Equal(0, raised);
  436. }
  437. }
  438. public class SelectRange
  439. {
  440. [Fact]
  441. public void SelectRange_Throws()
  442. {
  443. var target = CreateTarget();
  444. Assert.Throws<InvalidOperationException>(() => target.SelectRange(0, 10));
  445. }
  446. }
  447. public class Deselect
  448. {
  449. [Fact]
  450. public void Deselect_Clears_Current_Selection()
  451. {
  452. var target = CreateTarget();
  453. var raised = 0;
  454. target.SelectedIndex = 0;
  455. target.SelectionChanged += (s, e) =>
  456. {
  457. Assert.Equal(new[] { 0 }, e.DeselectedIndexes);
  458. Assert.Equal(new[] { "foo" }, e.DeselectedItems);
  459. Assert.Empty(e.SelectedIndexes);
  460. Assert.Empty(e.SelectedItems);
  461. ++raised;
  462. };
  463. target.Deselect(0);
  464. Assert.Equal(-1, target.SelectedIndex);
  465. Assert.Empty(target.SelectedIndexes);
  466. Assert.Null(target.SelectedItem);
  467. Assert.Empty(target.SelectedItems);
  468. Assert.Equal(1, raised);
  469. }
  470. [Fact]
  471. public void Deselect_Does_Nothing_For_Nonselected_Item()
  472. {
  473. var target = CreateTarget();
  474. var raised = 0;
  475. target.SelectedIndex = 1;
  476. target.SelectionChanged += (s, e) => ++raised;
  477. target.Deselect(0);
  478. Assert.Equal(1, target.SelectedIndex);
  479. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  480. Assert.Equal("bar", target.SelectedItem);
  481. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  482. Assert.Equal(0, raised);
  483. }
  484. }
  485. public class DeselectRange
  486. {
  487. [Fact]
  488. public void DeselectRange_Clears_Current_Selection_For_Intersecting_Range()
  489. {
  490. var target = CreateTarget();
  491. var raised = 0;
  492. target.SelectedIndex = 0;
  493. target.SelectionChanged += (s, e) =>
  494. {
  495. Assert.Equal(new[] { 0 }, e.DeselectedIndexes);
  496. Assert.Equal(new[] { "foo" }, e.DeselectedItems);
  497. Assert.Empty(e.SelectedIndexes);
  498. Assert.Empty(e.SelectedItems);
  499. ++raised;
  500. };
  501. target.DeselectRange(0, 2);
  502. Assert.Equal(-1, target.SelectedIndex);
  503. Assert.Empty(target.SelectedIndexes);
  504. Assert.Null(target.SelectedItem);
  505. Assert.Empty(target.SelectedItems);
  506. Assert.Equal(1, raised);
  507. }
  508. [Fact]
  509. public void DeselectRange_Does_Nothing_For_Nonintersecting_Range()
  510. {
  511. var target = CreateTarget();
  512. var raised = 0;
  513. target.SelectedIndex = 0;
  514. target.SelectionChanged += (s, e) => ++raised;
  515. target.DeselectRange(1, 2);
  516. Assert.Equal(0, target.SelectedIndex);
  517. Assert.Equal(new[] { 0 }, target.SelectedIndexes);
  518. Assert.Equal("foo", target.SelectedItem);
  519. Assert.Equal(new[] { "foo" }, target.SelectedItems);
  520. Assert.Equal(0, raised);
  521. }
  522. }
  523. public class Clear
  524. {
  525. [Fact]
  526. public void Clear_Raises_SelectionChanged()
  527. {
  528. var target = CreateTarget();
  529. var raised = 0;
  530. target.Select(1);
  531. target.SelectionChanged += (s, e) =>
  532. {
  533. Assert.Equal(new[] { 1 }, e.DeselectedIndexes);
  534. Assert.Equal(new[] { "bar" }, e.DeselectedItems);
  535. Assert.Empty(e.SelectedIndexes);
  536. Assert.Empty(e.SelectedItems);
  537. ++raised;
  538. };
  539. target.Clear();
  540. Assert.Equal(1, raised);
  541. }
  542. }
  543. public class AnchorIndex
  544. {
  545. [Fact]
  546. public void Setting_SelectedIndex_Sets_AnchorIndex()
  547. {
  548. var target = CreateTarget();
  549. var raised = 0;
  550. target.PropertyChanged += (s, e) =>
  551. {
  552. if (e.PropertyName == nameof(target.AnchorIndex))
  553. {
  554. ++raised;
  555. }
  556. };
  557. target.SelectedIndex = 1;
  558. Assert.Equal(1, target.AnchorIndex);
  559. Assert.Equal(1, raised);
  560. }
  561. [Fact]
  562. public void Setting_SelectedIndex_To_Minus_1_Doesnt_Clear_AnchorIndex()
  563. {
  564. var target = CreateTarget();
  565. var raised = 0;
  566. target.SelectedIndex = 1;
  567. target.PropertyChanged += (s, e) =>
  568. {
  569. if (e.PropertyName == nameof(target.AnchorIndex))
  570. {
  571. ++raised;
  572. }
  573. };
  574. target.SelectedIndex = -1;
  575. Assert.Equal(1, target.AnchorIndex);
  576. Assert.Equal(0, raised);
  577. }
  578. [Fact]
  579. public void Select_Sets_AnchorIndex()
  580. {
  581. var target = CreateTarget();
  582. var raised = 0;
  583. target.PropertyChanged += (s, e) =>
  584. {
  585. if (e.PropertyName == nameof(target.AnchorIndex))
  586. {
  587. ++raised;
  588. }
  589. };
  590. target.Select(1);
  591. Assert.Equal(1, target.AnchorIndex);
  592. Assert.Equal(1, raised);
  593. }
  594. [Fact]
  595. public void Deselect_Doesnt_Clear_AnchorIndex()
  596. {
  597. var target = CreateTarget();
  598. var raised = 0;
  599. target.Select(1);
  600. target.PropertyChanged += (s, e) =>
  601. {
  602. if (e.PropertyName == nameof(target.AnchorIndex))
  603. {
  604. ++raised;
  605. }
  606. };
  607. target.Deselect(1);
  608. Assert.Equal(1, target.AnchorIndex);
  609. Assert.Equal(0, raised);
  610. }
  611. [Fact]
  612. public void Raises_PropertyChanged()
  613. {
  614. var target = CreateTarget();
  615. var raised = 0;
  616. target.PropertyChanged += (s, e) =>
  617. {
  618. if (e.PropertyName == nameof(target.AnchorIndex))
  619. {
  620. ++raised;
  621. }
  622. };
  623. target.SelectedIndex = 1;
  624. Assert.Equal(1, raised);
  625. }
  626. }
  627. public class SingleSelect
  628. {
  629. [Fact]
  630. public void Converting_To_Multiple_Selection_Preserves_Selection()
  631. {
  632. var target = CreateTarget();
  633. var raised = 0;
  634. target.SelectedIndex = 1;
  635. target.SelectionChanged += (s, e) => ++raised;
  636. target.SingleSelect = false;
  637. Assert.Equal(1, target.SelectedIndex);
  638. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  639. Assert.Equal("bar", target.SelectedItem);
  640. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  641. Assert.Equal(0, raised);
  642. }
  643. [Fact]
  644. public void Raises_PropertyChanged()
  645. {
  646. var target = CreateTarget();
  647. var raised = 0;
  648. target.PropertyChanged += (s, e) =>
  649. {
  650. if (e.PropertyName == nameof(target.SingleSelect))
  651. {
  652. ++raised;
  653. }
  654. };
  655. target.SingleSelect = false;
  656. Assert.Equal(1, raised);
  657. }
  658. }
  659. public class CollectionChanges
  660. {
  661. [Fact]
  662. public void Adding_Item_Before_Selected_Item_Updates_Indexes()
  663. {
  664. var target = CreateTarget();
  665. var data = (AvaloniaList<string>)target.Source!;
  666. var selectionChangedRaised = 0;
  667. var indexesChangedRaised = 0;
  668. var selectedIndexRaised = 0;
  669. target.SelectedIndex = 1;
  670. target.SelectionChanged += (s, e) => ++selectionChangedRaised;
  671. target.PropertyChanged += (s, e) =>
  672. {
  673. if (e.PropertyName == nameof(target.SelectedIndex))
  674. {
  675. ++selectedIndexRaised;
  676. }
  677. };
  678. target.IndexesChanged += (s, e) =>
  679. {
  680. Assert.Equal(0, e.StartIndex);
  681. Assert.Equal(1, e.Delta);
  682. ++indexesChangedRaised;
  683. };
  684. data.Insert(0, "new");
  685. Assert.Equal(2, target.SelectedIndex);
  686. Assert.Equal(new[] { 2 }, target.SelectedIndexes);
  687. Assert.Equal("bar", target.SelectedItem);
  688. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  689. Assert.Equal(2, target.AnchorIndex);
  690. Assert.Equal(1, indexesChangedRaised);
  691. Assert.Equal(1, selectedIndexRaised);
  692. Assert.Equal(0, selectionChangedRaised);
  693. }
  694. [Fact]
  695. public void Adding_Item_After_Selected_Doesnt_Raise_Events()
  696. {
  697. var target = CreateTarget();
  698. var data = (AvaloniaList<string>)target.Source!;
  699. var raised = 0;
  700. target.SelectedIndex = 1;
  701. target.PropertyChanged += (s, e) => ++raised;
  702. target.SelectionChanged += (s, e) => ++raised;
  703. target.IndexesChanged += (s, e) => ++raised;
  704. data.Insert(2, "new");
  705. Assert.Equal(1, target.SelectedIndex);
  706. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  707. Assert.Equal("bar", target.SelectedItem);
  708. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  709. Assert.Equal(1, target.AnchorIndex);
  710. Assert.Equal(0, raised);
  711. }
  712. [Fact]
  713. public void Removing_Selected_Item_Updates_State()
  714. {
  715. var target = CreateTarget();
  716. var data = (AvaloniaList<string>)target.Source!;
  717. var selectionChangedRaised = 0;
  718. var selectedIndexRaised = 0;
  719. target.Source = data;
  720. target.Select(1);
  721. target.PropertyChanged += (s, e) =>
  722. {
  723. if (e.PropertyName == nameof(target.SelectedIndex))
  724. {
  725. ++selectedIndexRaised;
  726. }
  727. };
  728. target.SelectionChanged += (s, e) =>
  729. {
  730. Assert.Empty(e.DeselectedIndexes);
  731. Assert.Equal(new[] { "bar" }, e.DeselectedItems);
  732. Assert.Empty(e.SelectedIndexes);
  733. Assert.Empty(e.SelectedItems);
  734. ++selectionChangedRaised;
  735. };
  736. data.RemoveAt(1);
  737. Assert.Equal(-1, target.SelectedIndex);
  738. Assert.Empty(target.SelectedIndexes);
  739. Assert.Null(target.SelectedItem);
  740. Assert.Empty(target.SelectedItems);
  741. Assert.Equal(-1, target.AnchorIndex);
  742. Assert.Equal(1, selectionChangedRaised);
  743. Assert.Equal(1, selectedIndexRaised);
  744. }
  745. [Fact]
  746. public void Removing_Item_Before_Selected_Item_Updates_Indexes()
  747. {
  748. var target = CreateTarget();
  749. var data = (AvaloniaList<string>)target.Source!;
  750. var selectionChangedRaised = 0;
  751. var indexesChangedraised = 0;
  752. target.SelectedIndex = 1;
  753. target.SelectionChanged += (s, e) => ++selectionChangedRaised;
  754. target.IndexesChanged += (s, e) =>
  755. {
  756. Assert.Equal(0, e.StartIndex);
  757. Assert.Equal(-1, e.Delta);
  758. ++indexesChangedraised;
  759. };
  760. data.RemoveAt(0);
  761. Assert.Equal(0, target.SelectedIndex);
  762. Assert.Equal(new[] { 0 }, target.SelectedIndexes);
  763. Assert.Equal("bar", target.SelectedItem);
  764. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  765. Assert.Equal(0, target.AnchorIndex);
  766. Assert.Equal(1, indexesChangedraised);
  767. Assert.Equal(0, selectionChangedRaised);
  768. }
  769. [Fact]
  770. public void Removing_Item_After_Selected_Doesnt_Raise_Events()
  771. {
  772. var target = CreateTarget();
  773. var data = (AvaloniaList<string>)target.Source!;
  774. var raised = 0;
  775. target.SelectedIndex = 1;
  776. target.PropertyChanged += (s, e) => ++raised;
  777. target.SelectionChanged += (s, e) => ++raised;
  778. target.IndexesChanged += (s, e) => ++raised;
  779. data.RemoveAt(2);
  780. Assert.Equal(1, target.SelectedIndex);
  781. Assert.Equal(new[] { 1 }, target.SelectedIndexes);
  782. Assert.Equal("bar", target.SelectedItem);
  783. Assert.Equal(new[] { "bar" }, target.SelectedItems);
  784. Assert.Equal(1, target.AnchorIndex);
  785. Assert.Equal(0, raised);
  786. }
  787. [Fact]
  788. public void Replacing_Selected_Item_Updates_State()
  789. {
  790. var target = CreateTarget();
  791. var data = (AvaloniaList<string>)target.Source!;
  792. var selectionChangedRaised = 0;
  793. var selectedIndexRaised = 0;
  794. target.Source = data;
  795. target.Select(1);
  796. target.PropertyChanged += (s, e) =>
  797. {
  798. if (e.PropertyName == nameof(target.SelectedIndex))
  799. {
  800. ++selectedIndexRaised;
  801. }
  802. };
  803. target.SelectionChanged += (s, e) =>
  804. {
  805. Assert.Empty(e.DeselectedIndexes);
  806. Assert.Equal(new[] { "bar" }, e.DeselectedItems);
  807. Assert.Empty(e.SelectedIndexes);
  808. Assert.Empty(e.SelectedItems);
  809. ++selectionChangedRaised;
  810. };
  811. data[1] = "new";
  812. Assert.Equal(-1, target.SelectedIndex);
  813. Assert.Empty(target.SelectedIndexes);
  814. Assert.Null(target.SelectedItem);
  815. Assert.Empty(target.SelectedItems);
  816. Assert.Equal(-1, target.AnchorIndex);
  817. Assert.Equal(1, selectionChangedRaised);
  818. Assert.Equal(1, selectedIndexRaised);
  819. }
  820. [Fact]
  821. public void Resetting_Source_Updates_State()
  822. {
  823. var target = CreateTarget();
  824. var data = (AvaloniaList<string>)target.Source!;
  825. var selectionChangedRaised = 0;
  826. var selectedIndexRaised = 0;
  827. var resetRaised = 0;
  828. target.Source = data;
  829. target.Select(1);
  830. target.PropertyChanged += (s, e) =>
  831. {
  832. if (e.PropertyName == nameof(target.SelectedIndex))
  833. {
  834. ++selectedIndexRaised;
  835. }
  836. };
  837. target.SelectionChanged += (s, e) => ++selectionChangedRaised;
  838. target.SourceReset += (s, e) => ++resetRaised;
  839. data.Clear();
  840. Assert.Equal(-1, target.SelectedIndex);
  841. Assert.Empty(target.SelectedIndexes);
  842. Assert.Null(target.SelectedItem);
  843. Assert.Empty(target.SelectedItems);
  844. Assert.Equal(-1, target.AnchorIndex);
  845. Assert.Equal(0, selectionChangedRaised);
  846. Assert.Equal(1, resetRaised);
  847. Assert.Equal(1, selectedIndexRaised);
  848. }
  849. }
  850. public class BatchUpdate
  851. {
  852. [Fact]
  853. public void Changes_Do_Not_Take_Effect_Until_EndUpdate_Called()
  854. {
  855. var target = CreateTarget();
  856. target.BeginBatchUpdate();
  857. target.Select(0);
  858. Assert.Equal(-1, target.SelectedIndex);
  859. target.EndBatchUpdate();
  860. Assert.Equal(0, target.SelectedIndex);
  861. }
  862. [Fact]
  863. public void Correctly_Batches_Clear_SelectedIndex()
  864. {
  865. var target = CreateTarget();
  866. var raised = 0;
  867. target.SelectedIndex = 2;
  868. target.SelectionChanged += (s, e) => ++raised;
  869. using (target.BatchUpdate())
  870. {
  871. target.Clear();
  872. target.SelectedIndex = 2;
  873. }
  874. Assert.Equal(0, raised);
  875. }
  876. }
  877. public class LostSelection
  878. {
  879. [Fact]
  880. public void LostSelection_Called_On_Clear()
  881. {
  882. var target = CreateTarget();
  883. var raised = 0;
  884. target.SelectedIndex = 1;
  885. target.SelectionChanged += (s, e) =>
  886. {
  887. Assert.Equal(new[] { 1 }, e.DeselectedIndexes);
  888. Assert.Equal(new[] { "bar" }, e.DeselectedItems);
  889. Assert.Equal(new[] { 0 }, e.SelectedIndexes);
  890. Assert.Equal(new[] { "foo" }, e.SelectedItems);
  891. ++raised;
  892. };
  893. target.LostSelection += (s, e) =>
  894. {
  895. target.Select(0);
  896. };
  897. target.Clear();
  898. Assert.Equal(0, target.SelectedIndex);
  899. Assert.Equal(1, raised);
  900. }
  901. [Fact]
  902. public void LostSelection_Called_When_SelectedItem_Removed()
  903. {
  904. var target = CreateTarget();
  905. var data = (AvaloniaList<string>)target.Source!;
  906. var raised = 0;
  907. target.SelectedIndex = 1;
  908. target.SelectionChanged += (s, e) =>
  909. {
  910. Assert.Empty(e.DeselectedIndexes);
  911. Assert.Equal(new[] { "bar" }, e.DeselectedItems);
  912. Assert.Equal(new[] { 0 }, e.SelectedIndexes);
  913. Assert.Equal(new[] { "foo" }, e.SelectedItems);
  914. ++raised;
  915. };
  916. target.LostSelection += (s, e) =>
  917. {
  918. target.Select(0);
  919. };
  920. data.RemoveAt(1);
  921. Assert.Equal(0, target.SelectedIndex);
  922. Assert.Equal(1, raised);
  923. }
  924. [Fact]
  925. public void LostSelection_Not_Called_With_Old_Source_When_Changing_Source()
  926. {
  927. var target = CreateTarget();
  928. var data = (AvaloniaList<string>)target.Source!;
  929. var raised = 0;
  930. target.LostSelection += (s, e) =>
  931. {
  932. if (target.Source == data)
  933. {
  934. ++raised;
  935. }
  936. };
  937. target.Source = null;
  938. Assert.Equal(0, raised);
  939. }
  940. }
  941. public class UntypedInterface
  942. {
  943. [Fact]
  944. public void Raises_Untyped_SelectionChanged_Event()
  945. {
  946. var target = CreateTarget();
  947. var raised = 0;
  948. target.SelectedIndex = 1;
  949. ((ISelectionModel)target).SelectionChanged += (s, e) =>
  950. {
  951. Assert.Equal(new[] { 1 }, e.DeselectedIndexes);
  952. Assert.Equal(new[] { "bar" }, e.DeselectedItems);
  953. Assert.Equal(new[] { 2 }, e.SelectedIndexes);
  954. Assert.Equal(new[] { "baz" }, e.SelectedItems);
  955. ++raised;
  956. };
  957. target.SelectedIndex = 2;
  958. Assert.Equal(1, raised);
  959. }
  960. }
  961. private static SelectionModel<string?> CreateTarget(bool createData = true)
  962. {
  963. var result = new SelectionModel<string?> { SingleSelect = true };
  964. if (createData)
  965. {
  966. result.Source = new AvaloniaList<string> { "foo", "bar", "baz" };
  967. }
  968. return result;
  969. }
  970. }
  971. }