| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384 |
- // This source file is adapted from the WinUI project.
- // (https://github.com/microsoft/microsoft-ui-xaml)
- //
- // Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Collections.Specialized;
- using System.ComponentModel;
- using System.Linq;
- using System.Reactive.Linq;
- using Avalonia.Collections;
- using Avalonia.Diagnostics;
- using ReactiveUI;
- using Xunit;
- using Xunit.Abstractions;
- namespace Avalonia.Controls.UnitTests
- {
- public class SelectionModelTests
- {
- private readonly ITestOutputHelper _output;
- public SelectionModelTests(ITestOutputHelper output)
- {
- _output = output;
- }
- [Fact]
- public void ValidateOneLevelSingleSelectionNoSource()
- {
- SelectionModel selectionModel = new SelectionModel() { SingleSelect = true };
- _output.WriteLine("No source set.");
- Select(selectionModel, 4, true);
- ValidateSelection(selectionModel, new List<IndexPath>() { Path(4) });
- Select(selectionModel, 4, false);
- ValidateSelection(selectionModel, new List<IndexPath>() { });
- }
- [Fact]
- public void ValidateOneLevelSingleSelection()
- {
- SelectionModel selectionModel = new SelectionModel() { SingleSelect = true };
- _output.WriteLine("Set the source to 10 items");
- selectionModel.Source = Enumerable.Range(0, 10).ToList();
- Select(selectionModel, 3, true);
- ValidateSelection(selectionModel, new List<IndexPath>() { Path(3) }, new List<IndexPath>() { Path() });
- Select(selectionModel, 3, false);
- ValidateSelection(selectionModel, new List<IndexPath>() { });
- }
- [Fact]
- public void ValidateSelectionChangedEvent()
- {
- SelectionModel selectionModel = new SelectionModel();
- selectionModel.Source = Enumerable.Range(0, 10).ToList();
- int selectionChangedFiredCount = 0;
- selectionModel.SelectionChanged += delegate (object sender, SelectionModelSelectionChangedEventArgs args)
- {
- selectionChangedFiredCount++;
- ValidateSelection(selectionModel, new List<IndexPath>() { Path(4) }, new List<IndexPath>() { Path() });
- };
- Select(selectionModel, 4, true);
- ValidateSelection(selectionModel, new List<IndexPath>() { Path(4) }, new List<IndexPath>() { Path() });
- Assert.Equal(1, selectionChangedFiredCount);
- }
- [Fact]
- public void ValidateCanSetSelectedIndex()
- {
- var model = new SelectionModel();
- var ip = IndexPath.CreateFrom(34);
- model.SelectedIndex = ip;
- Assert.Equal(0, ip.CompareTo(model.SelectedIndex));
- }
- [Fact]
- public void ValidateOneLevelMultipleSelection()
- {
- SelectionModel selectionModel = new SelectionModel();
- selectionModel.Source = Enumerable.Range(0, 10).ToList();
- Select(selectionModel, 4, true);
- ValidateSelection(selectionModel, new List<IndexPath>() { Path(4) }, new List<IndexPath>() { Path() });
- SelectRangeFromAnchor(selectionModel, 8, true /* select */);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(4),
- Path(5),
- Path(6),
- Path(7),
- Path(8)
- },
- new List<IndexPath>() { Path() });
- ClearSelection(selectionModel);
- SetAnchorIndex(selectionModel, 6);
- SelectRangeFromAnchor(selectionModel, 3, true /* select */);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(3),
- Path(4),
- Path(5),
- Path(6)
- },
- new List<IndexPath>() { Path() });
- SetAnchorIndex(selectionModel, 4);
- SelectRangeFromAnchor(selectionModel, 5, false /* select */);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(3),
- Path(6)
- },
- new List<IndexPath>() { Path() });
- }
- [Fact]
- public void ValidateTwoLevelSingleSelection()
- {
- SelectionModel selectionModel = new SelectionModel();
- _output.WriteLine("Setting the source");
- selectionModel.Source = CreateNestedData(1 /* levels */ , 2 /* groupsAtLevel */, 2 /* countAtLeaf */);
- Select(selectionModel, 1, 1, true);
- ValidateSelection(selectionModel,
- new List<IndexPath>() { Path(1, 1) }, new List<IndexPath>() { Path(), Path(1) });
- Select(selectionModel, 1, 1, false);
- ValidateSelection(selectionModel, new List<IndexPath>() { });
- }
- [Fact]
- public void ValidateTwoLevelMultipleSelection()
- {
- SelectionModel selectionModel = new SelectionModel();
- _output.WriteLine("Setting the source");
- selectionModel.Source = CreateNestedData(1 /* levels */ , 3 /* groupsAtLevel */, 3 /* countAtLeaf */);
- Select(selectionModel, 1, 2, true);
- ValidateSelection(selectionModel, new List<IndexPath>() { Path(1, 2) }, new List<IndexPath>() { Path(), Path(1) });
- SelectRangeFromAnchor(selectionModel, 2, 2, true /* select */);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 2),
- Path(2), // Inner node should be selected since everything 2.* is selected
- Path(2, 0),
- Path(2, 1),
- Path(2, 2)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1)
- },
- 1 /* selectedInnerNodes */);
- ClearSelection(selectionModel);
- SetAnchorIndex(selectionModel, 2, 1);
- SelectRangeFromAnchor(selectionModel, 0, 1, true /* select */);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(0, 1),
- Path(0, 2),
- Path(1, 0),
- Path(1, 1),
- Path(1, 2),
- Path(1),
- Path(2, 0),
- Path(2, 1)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(0),
- Path(2),
- },
- 1 /* selectedInnerNodes */);
- SetAnchorIndex(selectionModel, 1, 1);
- SelectRangeFromAnchor(selectionModel, 2, 0, false /* select */);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(0, 1),
- Path(0, 2),
- Path(1, 0),
- Path(2, 1)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1),
- Path(0),
- Path(2),
- },
- 0 /* selectedInnerNodes */);
- ClearSelection(selectionModel);
- ValidateSelection(selectionModel, new List<IndexPath>() { });
- }
- [Fact]
- public void ValidateNestedSingleSelection()
- {
- SelectionModel selectionModel = new SelectionModel() { SingleSelect = true };
- _output.WriteLine("Setting the source");
- selectionModel.Source = CreateNestedData(3 /* levels */ , 2 /* groupsAtLevel */, 2 /* countAtLeaf */);
- var path = Path(1, 0, 1, 1);
- Select(selectionModel, path, true);
- ValidateSelection(selectionModel,
- new List<IndexPath>() { path },
- new List<IndexPath>()
- {
- Path(),
- Path(1),
- Path(1, 0),
- Path(1, 0, 1),
- });
- Select(selectionModel, Path(0, 0, 1, 0), true);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(0, 0, 1, 0)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(0),
- Path(0, 0),
- Path(0, 0, 1)
- });
- Select(selectionModel, Path(0, 0, 1, 0), false);
- ValidateSelection(selectionModel, new List<IndexPath>() { });
- }
- [Theory]
- [InlineData(true)]
- [InlineData(false)]
- public void ValidateNestedMultipleSelection(bool handleChildrenRequested)
- {
- SelectionModel selectionModel = new SelectionModel();
- List<IndexPath> sourcePaths = new List<IndexPath>();
- _output.WriteLine("Setting the source");
- selectionModel.Source = CreateNestedData(3 /* levels */ , 2 /* groupsAtLevel */, 4 /* countAtLeaf */);
- if (handleChildrenRequested)
- {
- selectionModel.ChildrenRequested += (object sender, SelectionModelChildrenRequestedEventArgs args) =>
- {
- _output.WriteLine("ChildrenRequestedIndexPath:" + args.SourceIndex);
- sourcePaths.Add(args.SourceIndex);
- args.Children = Observable.Return(args.Source as IEnumerable);
- };
- }
- var startPath = Path(1, 0, 1, 0);
- Select(selectionModel, startPath, true);
- ValidateSelection(selectionModel,
- new List<IndexPath>() { startPath },
- new List<IndexPath>()
- {
- Path(),
- Path(1),
- Path(1, 0),
- Path(1, 0, 1)
- });
- var endPath = Path(1, 1, 1, 0);
- SelectRangeFromAnchor(selectionModel, endPath, true /* select */);
- if (handleChildrenRequested)
- {
- // Validate SourceIndices.
- var expectedSourceIndices = new List<IndexPath>()
- {
- Path(1),
- Path(1, 0),
- Path(1, 0, 1),
- Path(1, 1),
- Path(1, 0, 1, 3),
- Path(1, 0, 1, 2),
- Path(1, 0, 1, 1),
- Path(1, 0, 1, 0),
- Path(1, 1, 1),
- Path(1, 1, 0),
- Path(1, 1, 0, 3),
- Path(1, 1, 0, 2),
- Path(1, 1, 0, 1),
- Path(1, 1, 0, 0),
- Path(1, 1, 1, 0)
- };
- Assert.Equal(expectedSourceIndices.Count, sourcePaths.Count);
- for (int i = 0; i < expectedSourceIndices.Count; i++)
- {
- Assert.True(AreEqual(expectedSourceIndices[i], sourcePaths[i]));
- }
- }
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 0),
- Path(1, 1),
- Path(1, 0, 1),
- Path(1, 0, 1, 0),
- Path(1, 0, 1, 1),
- Path(1, 0, 1, 2),
- Path(1, 0, 1, 3),
- Path(1, 1, 0),
- Path(1, 1, 1),
- Path(1, 1, 0, 0),
- Path(1, 1, 0, 1),
- Path(1, 1, 0, 2),
- Path(1, 1, 0, 3),
- Path(1, 1, 1, 0),
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1),
- Path(1, 0),
- Path(1, 1),
- Path(1, 1, 1),
- });
- ClearSelection(selectionModel);
- ValidateSelection(selectionModel, new List<IndexPath>() { });
- startPath = Path(0, 1, 0, 2);
- SetAnchorIndex(selectionModel, startPath);
- endPath = Path(0, 0, 0, 2);
- SelectRangeFromAnchor(selectionModel, endPath, true /* select */);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(0, 0),
- Path(0, 1),
- Path(0, 0, 0),
- Path(0, 0, 1),
- Path(0, 0, 0, 2),
- Path(0, 0, 0, 3),
- Path(0, 0, 1, 0),
- Path(0, 0, 1, 1),
- Path(0, 0, 1, 2),
- Path(0, 0, 1, 3),
- Path(0, 1, 0),
- Path(0, 1, 0, 0),
- Path(0, 1, 0, 1),
- Path(0, 1, 0, 2),
- },
- new List<IndexPath>()
- {
- Path(),
- Path(0),
- Path(0, 0),
- Path(0, 0, 0),
- Path(0, 1),
- Path(0, 1, 0),
- });
- startPath = Path(0, 1, 0, 2);
- SetAnchorIndex(selectionModel, startPath);
- endPath = Path(0, 0, 0, 2);
- SelectRangeFromAnchor(selectionModel, endPath, false /* select */);
- ValidateSelection(selectionModel, new List<IndexPath>() { });
- }
- [Fact]
- public void ValidateInserts()
- {
- var data = new ObservableCollection<int>(Enumerable.Range(0, 10));
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.Select(3);
- selectionModel.Select(4);
- selectionModel.Select(5);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(3),
- Path(4),
- Path(5),
- },
- new List<IndexPath>()
- {
- Path()
- });
- _output.WriteLine("Insert in selected range: Inserting 3 items at index 4");
- data.Insert(4, 41);
- data.Insert(4, 42);
- data.Insert(4, 43);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(3),
- Path(7),
- Path(8),
- },
- new List<IndexPath>()
- {
- Path()
- });
- _output.WriteLine("Insert before selected range: Inserting 3 items at index 0");
- data.Insert(0, 100);
- data.Insert(0, 101);
- data.Insert(0, 102);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(6),
- Path(10),
- Path(11),
- },
- new List<IndexPath>()
- {
- Path()
- });
- _output.WriteLine("Insert after selected range: Inserting 3 items at index 12");
- data.Insert(12, 1000);
- data.Insert(12, 1001);
- data.Insert(12, 1002);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(6),
- Path(10),
- Path(11),
- },
- new List<IndexPath>()
- {
- Path()
- });
- }
- [Fact]
- public void ValidateGroupInserts()
- {
- var data = CreateNestedData(1 /* levels */ , 3 /* groupsAtLevel */, 3 /* countAtLeaf */);
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.Select(1, 1);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 1),
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1),
- });
- _output.WriteLine("Insert before selected range: Inserting item at group index 0");
- data.Insert(0, 100);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(2, 1)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(2),
- });
- _output.WriteLine("Insert after selected range: Inserting item at group index 3");
- data.Insert(3, 1000);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(2, 1)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(2),
- });
- }
- [Fact]
- public void ValidateRemoves()
- {
- var data = new ObservableCollection<int>(Enumerable.Range(0, 10));
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.Select(6);
- selectionModel.Select(7);
- selectionModel.Select(8);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(6),
- Path(7),
- Path(8)
- },
- new List<IndexPath>()
- {
- Path()
- });
- _output.WriteLine("Remove before selected range: Removing item at index 0");
- data.RemoveAt(0);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(5),
- Path(6),
- Path(7)
- },
- new List<IndexPath>()
- {
- Path()
- });
- _output.WriteLine("Remove from before to middle of selected range: Removing items at index 3, 4, 5");
- data.RemoveAt(3);
- data.RemoveAt(3);
- data.RemoveAt(3);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(3),
- Path(4)
- },
- new List<IndexPath>()
- {
- Path()
- });
- _output.WriteLine("Remove after selected range: Removing item at index 5");
- data.RemoveAt(5);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(3),
- Path(4)
- },
- new List<IndexPath>()
- {
- Path()
- });
- }
- [Fact]
- public void ValidateGroupRemoves()
- {
- var data = CreateNestedData(1 /* levels */ , 3 /* groupsAtLevel */, 3 /* countAtLeaf */);
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.Select(1, 1);
- selectionModel.Select(1, 2);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 1),
- Path(1, 2)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1),
- });
- _output.WriteLine("Remove before selected range: Removing item at group index 0");
- data.RemoveAt(0);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(0, 1),
- Path(0, 2)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(0),
- });
- _output.WriteLine("Remove after selected range: Removing item at group index 1");
- data.RemoveAt(1);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(0, 1),
- Path(0, 2)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(0),
- });
- _output.WriteLine("Remove group containing selected items");
- data.RemoveAt(0);
- ValidateSelection(selectionModel, new List<IndexPath>());
- }
- [Fact]
- public void CanReplaceItem()
- {
- var data = new ObservableCollection<int>(Enumerable.Range(0, 10));
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.Select(3);
- selectionModel.Select(4);
- selectionModel.Select(5);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(3),
- Path(4),
- Path(5),
- },
- new List<IndexPath>()
- {
- Path()
- });
- data[3] = 300;
- data[4] = 400;
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(5),
- },
- new List<IndexPath>()
- {
- Path()
- });
- }
- [Fact]
- public void ValidateGroupReplaceLosesSelection()
- {
- var data = CreateNestedData(1 /* levels */ , 3 /* groupsAtLevel */, 3 /* countAtLeaf */);
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.Select(1, 1);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 1)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1)
- });
- data[1] = new ObservableCollection<int>(Enumerable.Range(0, 5));
- ValidateSelection(selectionModel, new List<IndexPath>());
- }
- [Fact]
- public void ValidateClear()
- {
- var data = new ObservableCollection<int>(Enumerable.Range(0, 10));
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.Select(3);
- selectionModel.Select(4);
- selectionModel.Select(5);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(3),
- Path(4),
- Path(5),
- },
- new List<IndexPath>()
- {
- Path()
- });
- data.Clear();
- ValidateSelection(selectionModel, new List<IndexPath>());
- }
- [Fact]
- public void ValidateGroupClear()
- {
- var data = CreateNestedData(1 /* levels */ , 3 /* groupsAtLevel */, 3 /* countAtLeaf */);
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.Select(1, 1);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 1)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1)
- });
- (data[1] as IList).Clear();
- ValidateSelection(selectionModel, new List<IndexPath>());
- }
- // In some cases the leaf node might get a collection change that affects an ancestors selection
- // state. In this case we were not raising selection changed event. For example, if all elements
- // in a group are selected and a new item gets inserted - the parent goes from selected to partially
- // selected. In that case we need to raise the selection changed event so that the header containers
- // can show the correct visual.
- [Fact]
- public void ValidateEventWhenInnerNodeChangesSelectionState()
- {
- bool selectionChangedRaised = false;
- var data = CreateNestedData(1 /* levels */ , 3 /* groupsAtLevel */, 3 /* countAtLeaf */);
- var selectionModel = new SelectionModel();
- selectionModel.Source = data;
- selectionModel.SelectionChanged += (sender, args) => { selectionChangedRaised = true; };
- selectionModel.Select(1, 0);
- selectionModel.Select(1, 1);
- selectionModel.Select(1, 2);
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 0),
- Path(1, 1),
- Path(1, 2),
- Path(1)
- },
- new List<IndexPath>()
- {
- Path(),
- },
- 1 /* selectedInnerNodes */);
- _output.WriteLine("Inserting 1.0");
- selectionChangedRaised = false;
- (data[1] as AvaloniaList<object>).Insert(0, 100);
- Assert.True(selectionChangedRaised, "SelectionChanged event was not raised");
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 1),
- Path(1, 2),
- Path(1, 3),
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1),
- });
- _output.WriteLine("Removing 1.0");
- selectionChangedRaised = false;
- (data[1] as AvaloniaList<object>).RemoveAt(0);
- Assert.True(selectionChangedRaised, "SelectionChanged event was not raised");
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(1, 0),
- Path(1, 1),
- Path(1, 2),
- Path(1)
- },
- new List<IndexPath>()
- {
- Path(),
- },
- 1 /* selectedInnerNodes */);
- }
- [Fact]
- public void ValidatePropertyChangedEventIsRaised()
- {
- var selectionModel = new SelectionModel();
- _output.WriteLine("Set the source to 10 items");
- selectionModel.Source = Enumerable.Range(0, 10).ToList();
- bool selectedIndexChanged = false;
- bool selectedIndicesChanged = false;
- bool SelectedItemChanged = false;
- bool SelectedItemsChanged = false;
- bool AnchorIndexChanged = false;
- selectionModel.PropertyChanged += (sender, args) =>
- {
- switch (args.PropertyName)
- {
- case "SelectedIndex":
- selectedIndexChanged = true;
- break;
- case "SelectedIndices":
- selectedIndicesChanged = true;
- break;
- case "SelectedItem":
- SelectedItemChanged = true;
- break;
- case "SelectedItems":
- SelectedItemsChanged = true;
- break;
- case "AnchorIndex":
- AnchorIndexChanged = true;
- break;
- default:
- throw new InvalidOperationException();
- }
- };
- Select(selectionModel, 3, true);
- Assert.True(selectedIndexChanged);
- Assert.True(selectedIndicesChanged);
- Assert.True(SelectedItemChanged);
- Assert.True(SelectedItemsChanged);
- Assert.True(AnchorIndexChanged);
- }
- [Fact]
- public void CanExtendSelectionModelINPC()
- {
- var selectionModel = new CustomSelectionModel();
- bool intPropertyChanged = false;
- selectionModel.PropertyChanged += (sender, args) =>
- {
- if (args.PropertyName == "IntProperty")
- {
- intPropertyChanged = true;
- }
- };
- selectionModel.IntProperty = 5;
- Assert.True(intPropertyChanged);
- }
- [Fact]
- public void SelectRangeRegressionTest()
- {
- var selectionModel = new SelectionModel()
- {
- Source = CreateNestedData(1, 2, 3)
- };
- // length of start smaller than end used to cause an out of range error.
- selectionModel.SelectRange(IndexPath.CreateFrom(0), IndexPath.CreateFrom(1, 1));
- ValidateSelection(selectionModel,
- new List<IndexPath>()
- {
- Path(0),
- Path(1),
- Path(0, 0),
- Path(0, 1),
- Path(0, 2),
- Path(1, 0),
- Path(1, 1)
- },
- new List<IndexPath>()
- {
- Path(),
- Path(1)
- });
- }
- [Fact]
- public void Should_Listen_For_Changes_After_Deselect()
- {
- var target = new SelectionModel();
- var data = CreateNestedData(1, 2, 3);
- target.Source = data;
- target.Select(1, 0);
- target.Deselect(1, 0);
- target.Select(1, 0);
- ((AvaloniaList<object>)data[1]).Insert(0, "foo");
- Assert.Equal(new IndexPath(1, 1), target.SelectedIndex);
- }
- [Fact]
- public void Selecting_Item_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(4) }, e.SelectedIndices);
- Assert.Equal(new object[] { 4 }, e.SelectedItems);
- ++raised;
- };
- target.Select(4);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Selecting_Already_Selected_Item_Doesnt_Raise_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.Select(4);
- target.SelectionChanged += (s, e) => ++raised;
- target.Select(4);
- Assert.Equal(0, raised);
- }
- [Fact]
- public void SingleSelecting_Item_Raises_SelectionChanged()
- {
- var target = new SelectionModel { SingleSelect = true };
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.Select(3);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Equal(new[] { new IndexPath(3) }, e.DeselectedIndices);
- Assert.Equal(new object[] { 3 }, e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(4) }, e.SelectedIndices);
- Assert.Equal(new object[] { 4 }, e.SelectedItems);
- ++raised;
- };
- target.Select(4);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void SingleSelecting_Already_Selected_Item_Doesnt_Raise_SelectionChanged()
- {
- var target = new SelectionModel { SingleSelect = true };
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.Select(4);
- target.SelectionChanged += (s, e) => ++raised;
- target.Select(4);
- Assert.Equal(0, raised);
- }
- [Fact]
- public void Selecting_Item_With_Group_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = CreateNestedData(1, 2, 3);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(1, 1) }, e.SelectedIndices);
- Assert.Equal(new object[] { 4 }, e.SelectedItems);
- ++raised;
- };
- target.Select(1, 1);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void SelectAt_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = CreateNestedData(1, 2, 3);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(1, 1) }, e.SelectedIndices);
- Assert.Equal(new object[] { 4 }, e.SelectedItems);
- ++raised;
- };
- target.SelectAt(new IndexPath(1, 1));
- Assert.Equal(1, raised);
- }
- [Fact]
- public void SelectAll_Raises_SelectionChanged()
- {
- var target = new SelectionModel { SingleSelect = true };
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.SelectionChanged += (s, e) =>
- {
- var expected = Enumerable.Range(0, 10);
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(expected.Select(x => new IndexPath(x)), e.SelectedIndices);
- Assert.Equal(expected, e.SelectedItems.Cast<int>());
- ++raised;
- };
- target.SelectAll();
- Assert.Equal(1, raised);
- }
- [Fact]
- public void SelectAll_With_Already_Selected_Items_Raises_SelectionChanged()
- {
- var target = new SelectionModel { SingleSelect = true };
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.Select(4);
- target.SelectionChanged += (s, e) =>
- {
- var expected = Enumerable.Range(0, 10).Except(new[] { 4 });
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(expected.Select(x => new IndexPath(x)), e.SelectedIndices);
- Assert.Equal(expected, e.SelectedItems.Cast<int>());
- ++raised;
- };
- target.SelectAll();
- Assert.Equal(1, raised);
- }
- [Fact]
- public void SelectRangeFromAnchor_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.SelectionChanged += (s, e) =>
- {
- var expected = Enumerable.Range(4, 3);
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(expected.Select(x => new IndexPath(x)), e.SelectedIndices);
- Assert.Equal(expected, e.SelectedItems.Cast<int>());
- ++raised;
- };
- target.AnchorIndex = new IndexPath(4);
- target.SelectRangeFromAnchor(6);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void SelectRangeFromAnchor_With_Group_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = CreateNestedData(1, 2, 10);
- target.SelectionChanged += (s, e) =>
- {
- var expected = Enumerable.Range(11, 6);
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(expected.Select(x => new IndexPath(x / 10, x % 10)), e.SelectedIndices);
- Assert.Equal(expected, e.SelectedItems.Cast<int>());
- ++raised;
- };
- target.AnchorIndex = new IndexPath(1, 1);
- target.SelectRangeFromAnchor(1, 6);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void SelectRangeFromAnchorTo_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = CreateNestedData(1, 2, 10);
- target.SelectionChanged += (s, e) =>
- {
- var expected = Enumerable.Range(11, 6);
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(expected.Select(x => new IndexPath(x / 10, x % 10)), e.SelectedIndices);
- Assert.Equal(expected, e.SelectedItems.Cast<int>());
- ++raised;
- };
- target.AnchorIndex = new IndexPath(1, 1);
- target.SelectRangeFromAnchorTo(new IndexPath(1, 6));
- Assert.Equal(1, raised);
- }
- [Fact]
- public void ClearSelection_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.Select(4);
- target.Select(5);
- target.SelectionChanged += (s, e) =>
- {
- var expected = Enumerable.Range(4, 2);
- Assert.Equal(expected.Select(x => new IndexPath(x)), e.DeselectedIndices);
- Assert.Equal(expected, e.DeselectedItems.Cast<int>());
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- target.ClearSelection();
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Clearing_Nested_Selection_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = CreateNestedData(1, 2, 3);
- target.Select(1, 1);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Equal(new[] { new IndexPath(1, 1) }, e.DeselectedIndices);
- Assert.Equal(new object[] { 4 }, e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- target.ClearSelection();
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Changing_Source_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.Select(4);
- target.Select(5);
- target.SelectionChanged += (s, e) =>
- {
- var expected = Enumerable.Range(4, 2);
- Assert.Equal(expected.Select(x => new IndexPath(x)), e.DeselectedIndices);
- Assert.Equal(expected, e.DeselectedItems.Cast<int>());
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- target.Source = Enumerable.Range(20, 10).ToList();
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Setting_SelectedIndex_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.Select(4);
- target.Select(5);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Equal(new[] { new IndexPath(4), new IndexPath(5) }, e.DeselectedIndices);
- Assert.Equal(new object[] { 4, 5 }, e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(6) }, e.SelectedIndices);
- Assert.Equal(new object[] { 6 }, e.SelectedItems);
- ++raised;
- };
- target.SelectedIndex = new IndexPath(6);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Removing_Selected_Item_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var data = new ObservableCollection<int>(Enumerable.Range(0, 10));
- var raised = 0;
- target.Source = data;
- target.Select(4);
- target.Select(5);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Equal(new object[] { 4 }, e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- data.Remove(4);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Removing_Selected_Child_Item_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var data = CreateNestedData(1, 2, 3);
- var raised = 0;
- target.Source = data;
- target.SelectRange(new IndexPath(0), new IndexPath(1, 1));
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Equal(new object[] { 1}, e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- ((AvaloniaList<object>)data[0]).RemoveAt(1);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Removing_Selected_Item_With_Children_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var data = CreateNestedData(1, 2, 3);
- var raised = 0;
- target.Source = data;
- target.SelectRange(new IndexPath(0), new IndexPath(1, 1));
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Equal(new object[] { new AvaloniaList<int> { 0, 1, 2 }, 0, 1, 2 }, e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- data.RemoveAt(0);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Removing_Unselected_Item_Before_Selected_Item_Raises_SelectionChanged()
- {
- var target = new SelectionModel();
- var data = new ObservableCollection<int>(Enumerable.Range(0, 10));
- var raised = 0;
- target.Source = data;
- target.Select(8);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- data.Remove(6);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void Removing_Unselected_Item_After_Selected_Item_Doesnt_Raise_SelectionChanged()
- {
- var target = new SelectionModel();
- var data = new ObservableCollection<int>(Enumerable.Range(0, 10));
- var raised = 0;
- target.Source = data;
- target.Select(4);
- target.SelectionChanged += (s, e) => ++raised;
- data.Remove(6);
- Assert.Equal(0, raised);
- }
- [Fact]
- public void Disposing_Unhooks_CollectionChanged_Handlers()
- {
- var data = CreateNestedData(2, 2, 2);
- var target = new SelectionModel { Source = data };
- target.SelectAll();
- VerifyCollectionChangedHandlers(1, data);
- target.Dispose();
- VerifyCollectionChangedHandlers(0, data);
- }
- [Fact]
- public void Clearing_Selection_Unhooks_CollectionChanged_Handlers()
- {
- var data = CreateNestedData(2, 2, 2);
- var target = new SelectionModel { Source = data };
- target.SelectAll();
- VerifyCollectionChangedHandlers(1, data);
- target.ClearSelection();
- // Root subscription not unhooked until SelectionModel is disposed.
- Assert.Equal(1, GetSubscriberCount(data));
- foreach (AvaloniaList<object> i in data)
- {
- VerifyCollectionChangedHandlers(0, i);
- }
- }
- [Fact]
- public void Removing_Item_Unhooks_CollectionChanged_Handlers()
- {
- var data = CreateNestedData(2, 2, 2);
- var target = new SelectionModel { Source = data };
- target.SelectAll();
- var toRemove = (AvaloniaList<object>)data[1];
- data.Remove(toRemove);
- Assert.Equal(0, GetSubscriberCount(toRemove));
- }
- [Fact]
- public void SelectRange_Behaves_The_Same_As_Multiple_Selects()
- {
- var data = new[] { 1, 2, 3 };
- var target = new SelectionModel { Source = data };
- target.Select(1);
- Assert.Equal(new[] { IndexPath.CreateFrom(1) }, target.SelectedIndices);
- target.ClearSelection();
- target.SelectRange(new IndexPath(1), new IndexPath(1));
- Assert.Equal(new[] { IndexPath.CreateFrom(1) }, target.SelectedIndices);
- }
- [Fact]
- public void SelectRange_Behaves_The_Same_As_Multiple_Selects_Nested()
- {
- var data = CreateNestedData(3, 2, 2);
- var target = new SelectionModel { Source = data };
- target.Select(1);
- Assert.Equal(new[] { IndexPath.CreateFrom(1) }, target.SelectedIndices);
- target.ClearSelection();
- target.SelectRange(new IndexPath(1), new IndexPath(1));
- Assert.Equal(new[] { IndexPath.CreateFrom(1) }, target.SelectedIndices);
- }
- [Fact]
- public void Should_Not_Treat_Strings_As_Nested_Selections()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data };
- target.SelectAll();
- Assert.Equal(3, target.SelectedItems.Count);
- }
- [Fact]
- public void Not_Enumerating_Changes_Does_Not_Prevent_Further_Operations()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data };
- target.SelectionChanged += (s, e) => { };
- target.SelectAll();
- target.ClearSelection();
- }
- [Fact]
- public void Can_Change_Selection_From_SelectionChanged()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data };
- var raised = 0;
- target.SelectionChanged += (s, e) =>
- {
- if (raised++ == 0)
- {
- target.ClearSelection();
- }
- };
- target.SelectAll();
- Assert.Equal(2, raised);
- }
- [Fact]
- public void Raises_SelectionChanged_With_No_Source()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(1) }, e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- target.Select(1);
- Assert.Equal(new[] { new IndexPath(1) }, target.SelectedIndices);
- Assert.Empty(target.SelectedItems);
- }
- [Fact]
- public void Raises_SelectionChanged_With_Items_After_Source_Is_Set()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Select(1);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(1) }, e.SelectedIndices);
- Assert.Equal(new[] { "bar" }, e.SelectedItems);
- ++raised;
- };
- target.Source = new[] { "foo", "bar", "baz" };
- Assert.Equal(1, raised);
- }
- [Fact]
- public void RetainSelectionOnReset_Retains_Selection_On_Reset()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data, RetainSelectionOnReset = true };
- target.SelectRange(new IndexPath(1), new IndexPath(2));
- data.Reset();
- Assert.Equal(new[] { new IndexPath(1), new IndexPath(2) }, target.SelectedIndices);
- Assert.Equal(new[] { "bar", "baz" }, target.SelectedItems);
- }
- [Fact]
- public void RetainSelectionOnReset_Retains_Correct_Selection_After_Deselect()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data, RetainSelectionOnReset = true };
- target.SelectRange(new IndexPath(1), new IndexPath(2));
- target.Deselect(2);
- data.Reset();
- Assert.Equal(new[] { new IndexPath(1) }, target.SelectedIndices);
- Assert.Equal(new[] { "bar" }, target.SelectedItems);
- }
- [Fact]
- public void RetainSelectionOnReset_Retains_Correct_Selection_After_Remove_1()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data, RetainSelectionOnReset = true };
- target.SelectRange(new IndexPath(1), new IndexPath(2));
- data.RemoveAt(2);
- data.Reset(new[] { "foo", "bar", "baz" });
- Assert.Equal(new[] { new IndexPath(1) }, target.SelectedIndices);
- Assert.Equal(new[] { "bar" }, target.SelectedItems);
- }
- [Fact]
- public void RetainSelectionOnReset_Retains_Correct_Selection_After_Remove_2()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data, RetainSelectionOnReset = true };
- target.SelectRange(new IndexPath(1), new IndexPath(2));
- data.RemoveAt(0);
- data.Reset(new[] { "foo", "bar", "baz" });
- Assert.Equal(new[] { new IndexPath(1), new IndexPath(2) }, target.SelectedIndices);
- Assert.Equal(new[] { "bar", "baz" }, target.SelectedItems);
- }
- [Fact]
- public void RetainSelectionOnReset_Retains_No_Selection_After_Clear()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data, RetainSelectionOnReset = true };
- target.SelectRange(new IndexPath(1), new IndexPath(2));
- target.ClearSelection();
- data.Reset();
- Assert.Empty(target.SelectedIndices);
- Assert.Empty(target.SelectedItems);
- }
- [Fact]
- public void RetainSelectionOnReset_Retains_Correct_Selection_After_Two_Resets()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data, RetainSelectionOnReset = true };
- target.SelectRange(new IndexPath(1), new IndexPath(2));
- data.Reset(new[] { "foo", "bar" });
- data.Reset(new[] { "foo", "bar", "baz" });
- Assert.Equal(new[] { new IndexPath(1) }, target.SelectedIndices);
- Assert.Equal(new[] { "bar", }, target.SelectedItems);
- }
- [Fact]
- public void RetainSelectionOnReset_Raises_Empty_SelectionChanged_On_Reset_With_No_Changes()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data, RetainSelectionOnReset = true };
- var raised = 0;
- target.SelectRange(new IndexPath(1), new IndexPath(2));
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- data.Reset();
- }
- [Fact]
- public void RetainSelectionOnReset_Raises_SelectionChanged_On_Reset_With_Removed_Items()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data, RetainSelectionOnReset = true };
- var raised = 0;
- target.SelectRange(new IndexPath(1), new IndexPath(2));
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Equal(new[] { "bar" }, e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- ++raised;
- };
- data.Reset(new[] { "foo", "baz" });
- Assert.Equal(1, raised);
- }
- [Fact]
- public void RetainSelectionOnReset_Handles_Null_Source()
- {
- var data = new ResettingList<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { RetainSelectionOnReset = true };
- var raised = 0;
- target.SelectionChanged += (s, e) =>
- {
- if (raised == 0)
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(1) }, e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- }
- else if (raised == 1)
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(1) }, e.SelectedIndices);
- Assert.Equal(new[] { "bar" }, e.SelectedItems);
- }
- else if (raised == 3)
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- }
- ++raised;
- };
- target.Select(1);
- Assert.Equal(1, raised);
- target.Source = data;
- Assert.Equal(2, raised);
- Assert.Equal(new[] { new IndexPath(1) }, target.SelectedIndices);
- data.Reset(new[] { "qux", "foo", "bar", "baz" });
- Assert.Equal(3, raised);
- Assert.Equal(new[] { new IndexPath(2) }, target.SelectedIndices);
- }
-
- [Fact]
- public void Can_Batch_Update()
- {
- var target = new SelectionModel();
- var raised = 0;
- target.Source = Enumerable.Range(0, 10).ToList();
- target.Select(1);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Equal(new[] { new IndexPath(1) }, e.DeselectedIndices);
- Assert.Equal(new object[] { 1 }, e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(4) }, e.SelectedIndices);
- Assert.Equal(new object[] { 4 }, e.SelectedItems);
- ++raised;
- };
- using (target.Update())
- {
- target.Deselect(1);
- target.Select(4);
- }
- Assert.Equal(1, raised);
- }
- [Fact]
- public void AutoSelect_Selects_When_Enabled()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { Source = data };
- var raised = 0;
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(0) }, e.SelectedIndices);
- Assert.Equal(new[] { "foo" }, e.SelectedItems);
- ++raised;
- };
- target.AutoSelect = true;
- Assert.Equal(new IndexPath(0), target.SelectedIndex);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void AutoSelect_Selects_When_Source_Assigned()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { AutoSelect = true };
- var raised = 0;
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(0) }, e.SelectedIndices);
- Assert.Equal(new[] { "foo" }, e.SelectedItems);
- ++raised;
- };
- target.Source = data;
-
- Assert.Equal(new IndexPath(0), target.SelectedIndex);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void AutoSelect_Selects_When_New_Source_Assigned_And_Old_Source_Has_Selection()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { AutoSelect = true, Source = data };
- var raised = 0;
- target.SelectionChanged += (s, e) =>
- {
- if (raised == 0)
- {
- Assert.Equal(new[] { new IndexPath(0) }, e.DeselectedIndices);
- Assert.Equal(new[] { "foo" }, e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- }
- else
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(0) }, e.SelectedIndices);
- Assert.Equal(new[] { "newfoo" }, e.SelectedItems);
- }
- ++raised;
- };
- target.Source = new[] { "newfoo" };
- Assert.Equal(new IndexPath(0), target.SelectedIndex);
- Assert.Equal(2, raised);
- }
- [Fact]
- public void AutoSelect_Selects_When_First_Item_Added()
- {
- var data = new ObservableCollection<string>();
- var target = new SelectionModel { AutoSelect = true , Source = data };
- var raised = 0;
- target.SelectionChanged += (s, e) =>
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(0) }, e.SelectedIndices);
- Assert.Equal(new[] { "foo" }, e.SelectedItems);
- ++raised;
- };
- data.Add("foo");
- Assert.Equal(new IndexPath(0), target.SelectedIndex);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void AutoSelect_Selects_When_Selected_Item_Removed()
- {
- var data = new ObservableCollection<string> { "foo", "bar", "baz" };
- var target = new SelectionModel { AutoSelect = true, Source = data };
- var raised = 0;
- target.SelectedIndex = new IndexPath(2);
- target.SelectionChanged += (s, e) =>
- {
- if (raised == 0)
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Equal(new[] { "baz" }, e.DeselectedItems);
- Assert.Empty(e.SelectedIndices);
- Assert.Empty(e.SelectedItems);
- }
- else
- {
- Assert.Empty(e.DeselectedIndices);
- Assert.Empty(e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(0) }, e.SelectedIndices);
- Assert.Equal(new[] { "foo" }, e.SelectedItems);
- }
- ++raised;
- };
- data.RemoveAt(2);
- Assert.Equal(new IndexPath(0), target.SelectedIndex);
- Assert.Equal(2, raised);
- }
- [Fact]
- public void AutoSelect_Selects_On_Deselection()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { AutoSelect = true, Source = data };
- var raised = 0;
- target.SelectedIndex = new IndexPath(2);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Equal(new[] { new IndexPath(2) }, e.DeselectedIndices);
- Assert.Equal(new[] { "baz" }, e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(0) }, e.SelectedIndices);
- Assert.Equal(new[] { "foo" }, e.SelectedItems);
- ++raised;
- };
- target.Deselect(2);
- Assert.Equal(new IndexPath(0), target.SelectedIndex);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void AutoSelect_Selects_On_ClearSelection()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { AutoSelect = true, Source = data };
- var raised = 0;
- target.SelectedIndex = new IndexPath(2);
- target.SelectionChanged += (s, e) =>
- {
- Assert.Equal(new[] { new IndexPath(2) }, e.DeselectedIndices);
- Assert.Equal(new[] { "baz" }, e.DeselectedItems);
- Assert.Equal(new[] { new IndexPath(0) }, e.SelectedIndices);
- Assert.Equal(new[] { "foo" }, e.SelectedItems);
- ++raised;
- };
- target.ClearSelection();
- Assert.Equal(new IndexPath(0), target.SelectedIndex);
- Assert.Equal(1, raised);
- }
- [Fact]
- public void AutoSelect_Overrides_Deselecting_First_Item()
- {
- var data = new[] { "foo", "bar", "baz" };
- var target = new SelectionModel { AutoSelect = true, Source = data };
- var raised = 0;
- target.Select(0);
- target.SelectionChanged += (s, e) =>
- {
- ++raised;
- };
- target.Deselect(0);
- Assert.Equal(new IndexPath(0), target.SelectedIndex);
- Assert.Equal(0, raised);
- }
- [Fact]
- public void Can_Replace_Children_Collection()
- {
- var root = new Node("Root");
- var target = new SelectionModel { Source = new[] { root } };
- target.ChildrenRequested += (s, e) => e.Children = ((Node)e.Source).WhenAnyValue(x => x.Children);
- target.Select(0, 9);
- Assert.Equal("Child 9", ((Node)target.SelectedItem).Header);
- root.ReplaceChildren();
- Assert.Null(target.SelectedItem);
- }
- [Fact]
- public void Child_Resolver_Is_Unsubscribed_When_Source_Changed()
- {
- var root = new Node("Root");
- var target = new SelectionModel { Source = new[] { root } };
- target.ChildrenRequested += (s, e) => e.Children = ((Node)e.Source).WhenAnyValue(x => x.Children);
- target.Select(0, 9);
- Assert.Equal(1, root.PropertyChangedSubscriptions);
- target.Source = null;
- Assert.Equal(0, root.PropertyChangedSubscriptions);
- }
- [Fact]
- public void Child_Resolver_Is_Unsubscribed_When_Parent_Removed()
- {
- var root = new Node("Root");
- var target = new SelectionModel { Source = new[] { root } };
- var node = root.Children[1];
- var path = new IndexPath(new[] { 0, 1, 1 });
- target.ChildrenRequested += (s, e) => e.Children = ((Node)e.Source).WhenAnyValue(x => x.Children);
- target.SelectAt(path);
- Assert.Equal(1, node.PropertyChangedSubscriptions);
- root.ReplaceChildren();
- Assert.Equal(0, node.PropertyChangedSubscriptions);
- }
- private class Node : INotifyPropertyChanged
- {
- private ObservableCollection<Node> _children;
- private PropertyChangedEventHandler _propertyChanged;
- public Node(string header)
- {
- Header = header;
- }
- public string Header { get; }
- public ObservableCollection<Node> Children
- {
- get => _children ??= CreateChildren(10);
- private set
- {
- _children = value;
- _propertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Children)));
- }
- }
- public event PropertyChangedEventHandler PropertyChanged
- {
- add
- {
- _propertyChanged += value;
- ++PropertyChangedSubscriptions;
- }
- remove
- {
- _propertyChanged -= value;
- --PropertyChangedSubscriptions;
- }
- }
- public int PropertyChangedSubscriptions { get; private set; }
- public void ReplaceChildren()
- {
- Children = CreateChildren(5);
- }
- private ObservableCollection<Node> CreateChildren(int count)
- {
- return new ObservableCollection<Node>(
- Enumerable.Range(0, count).Select(x => new Node("Child " + x)));
- }
- }
- private int GetSubscriberCount(AvaloniaList<object> list)
- {
- return ((INotifyCollectionChangedDebug)list).GetCollectionChangedSubscribers()?.Length ?? 0;
- }
- private void VerifyCollectionChangedHandlers(int expected, AvaloniaList<object> list)
- {
- var count = GetSubscriberCount(list);
-
- Assert.Equal(expected, count);
- foreach (var i in list)
- {
- if (i is AvaloniaList<object> l)
- {
- VerifyCollectionChangedHandlers(expected, l);
- }
- }
- }
- private void Select(SelectionModel manager, int index, bool select)
- {
- _output.WriteLine((select ? "Selecting " : "DeSelecting ") + index);
- if (select)
- {
- manager.Select(index);
- }
- else
- {
- manager.Deselect(index);
- }
- }
- private void Select(SelectionModel manager, int groupIndex, int itemIndex, bool select)
- {
- _output.WriteLine((select ? "Selecting " : "DeSelecting ") + groupIndex + "." + itemIndex);
- if (select)
- {
- manager.Select(groupIndex, itemIndex);
- }
- else
- {
- manager.Deselect(groupIndex, itemIndex);
- }
- }
- private void Select(SelectionModel manager, IndexPath index, bool select)
- {
- _output.WriteLine((select ? "Selecting " : "DeSelecting ") + index);
- if (select)
- {
- manager.SelectAt(index);
- }
- else
- {
- manager.DeselectAt(index);
- }
- }
- private void SelectRangeFromAnchor(SelectionModel manager, int index, bool select)
- {
- _output.WriteLine("SelectRangeFromAnchor " + index + " select: " + select.ToString());
- if (select)
- {
- manager.SelectRangeFromAnchor(index);
- }
- else
- {
- manager.DeselectRangeFromAnchor(index);
- }
- }
- private void SelectRangeFromAnchor(SelectionModel manager, int groupIndex, int itemIndex, bool select)
- {
- _output.WriteLine("SelectRangeFromAnchor " + groupIndex + "." + itemIndex + " select:" + select.ToString());
- if (select)
- {
- manager.SelectRangeFromAnchor(groupIndex, itemIndex);
- }
- else
- {
- manager.DeselectRangeFromAnchor(groupIndex, itemIndex);
- }
- }
- private void SelectRangeFromAnchor(SelectionModel manager, IndexPath index, bool select)
- {
- _output.WriteLine("SelectRangeFromAnchor " + index + " select: " + select.ToString());
- if (select)
- {
- manager.SelectRangeFromAnchorTo(index);
- }
- else
- {
- manager.DeselectRangeFromAnchorTo(index);
- }
- }
- private void ClearSelection(SelectionModel manager)
- {
- _output.WriteLine("ClearSelection");
- manager.ClearSelection();
- }
- private void SetAnchorIndex(SelectionModel manager, int index)
- {
- _output.WriteLine("SetAnchorIndex " + index);
- manager.SetAnchorIndex(index);
- }
- private void SetAnchorIndex(SelectionModel manager, int groupIndex, int itemIndex)
- {
- _output.WriteLine("SetAnchor " + groupIndex + "." + itemIndex);
- manager.SetAnchorIndex(groupIndex, itemIndex);
- }
- private void SetAnchorIndex(SelectionModel manager, IndexPath index)
- {
- _output.WriteLine("SetAnchor " + index);
- manager.AnchorIndex = index;
- }
- private void ValidateSelection(
- SelectionModel selectionModel,
- List<IndexPath> expectedSelected,
- List<IndexPath> expectedPartialSelected = null,
- int selectedInnerNodes = 0)
- {
- _output.WriteLine("Validating Selection...");
- _output.WriteLine("Selection contains indices:");
- foreach (var index in selectionModel.SelectedIndices)
- {
- _output.WriteLine(" " + index.ToString());
- }
- _output.WriteLine("Selection contains items:");
- foreach (var item in selectionModel.SelectedItems)
- {
- _output.WriteLine(" " + item.ToString());
- }
- if (selectionModel.Source != null)
- {
- List<IndexPath> allIndices = GetIndexPathsInSource(selectionModel.Source);
- foreach (var index in allIndices)
- {
- bool? isSelected = selectionModel.IsSelectedWithPartialAt(index);
- if (Contains(expectedSelected, index) && !Contains(expectedPartialSelected, index))
- {
- Assert.True(isSelected.Value, index + " is Selected");
- }
- else if (expectedPartialSelected != null && Contains(expectedPartialSelected, index))
- {
- Assert.True(isSelected == null, index + " is partially Selected");
- }
- else
- {
- if (isSelected == null)
- {
- _output.WriteLine("*************" + index + " is null");
- Assert.True(false, "Expected false but got null");;
- }
- else
- {
- Assert.False(isSelected.Value, index + " is not Selected");
- }
- }
- }
- }
- else
- {
- foreach (var index in expectedSelected)
- {
- Assert.True(selectionModel.IsSelectedWithPartialAt(index), index + " is Selected");
- }
- }
- if (expectedSelected.Count > 0)
- {
- _output.WriteLine("SelectedIndex is " + selectionModel.SelectedIndex);
- Assert.Equal(expectedSelected[0], selectionModel.SelectedIndex);
- if (selectionModel.Source != null)
- {
- Assert.Equal(selectionModel.SelectedItem, GetData(selectionModel, expectedSelected[0]));
- }
- int itemsCount = selectionModel.SelectedItems.Count();
- Assert.Equal(selectionModel.Source != null ? expectedSelected.Count - selectedInnerNodes : 0, itemsCount);
- int indicesCount = selectionModel.SelectedIndices.Count();
- Assert.Equal(expectedSelected.Count - selectedInnerNodes, indicesCount);
- }
- _output.WriteLine("Validating Selection... done");
- }
- private object GetData(SelectionModel selectionModel, IndexPath indexPath)
- {
- var data = selectionModel.Source;
- for (int i = 0; i < indexPath.GetSize(); i++)
- {
- var listData = data as IList;
- data = listData[indexPath.GetAt(i)];
- }
- return data;
- }
- private bool AreEqual(IndexPath a, IndexPath b)
- {
- if (a.GetSize() != b.GetSize())
- {
- return false;
- }
- for (int i = 0; i < a.GetSize(); i++)
- {
- if (a.GetAt(i) != b.GetAt(i))
- {
- return false;
- }
- }
- return true;
- }
- private List<IndexPath> GetIndexPathsInSource(object source)
- {
- List<IndexPath> paths = new List<IndexPath>();
- Traverse(source, (TreeWalkNodeInfo node) =>
- {
- if (!paths.Contains(node.Path))
- {
- paths.Add(node.Path);
- }
- });
- _output.WriteLine("All Paths in source..");
- foreach (var path in paths)
- {
- _output.WriteLine(path.ToString());
- }
- _output.WriteLine("done.");
- return paths;
- }
- private static void Traverse(object root, Action<TreeWalkNodeInfo> nodeAction)
- {
- var pendingNodes = new Stack<TreeWalkNodeInfo>();
- IndexPath current = Path(null);
- pendingNodes.Push(new TreeWalkNodeInfo() { Current = root, Path = current });
- while (pendingNodes.Count > 0)
- {
- var currentNode = pendingNodes.Pop();
- var currentObject = currentNode.Current as IList;
- if (currentObject != null)
- {
- for (int i = currentObject.Count - 1; i >= 0; i--)
- {
- var child = currentObject[i];
- List<int> path = new List<int>();
- for (int idx = 0; idx < currentNode.Path.GetSize(); idx++)
- {
- path.Add(currentNode.Path.GetAt(idx));
- }
- path.Add(i);
- var childPath = IndexPath.CreateFromIndices(path);
- if (child != null)
- {
- pendingNodes.Push(new TreeWalkNodeInfo() { Current = child, Path = childPath });
- }
- }
- }
- nodeAction(currentNode);
- }
- }
- private bool Contains(List<IndexPath> list, IndexPath index)
- {
- bool contains = false;
- foreach (var item in list)
- {
- if (item.CompareTo(index) == 0)
- {
- contains = true;
- break;
- }
- }
- return contains;
- }
- public static AvaloniaList<object> CreateNestedData(int levels = 3, int groupsAtLevel = 5, int countAtLeaf = 10)
- {
- var nextData = 0;
- return CreateNestedData(levels, groupsAtLevel, countAtLeaf, ref nextData);
- }
- public static AvaloniaList<object> CreateNestedData(
- int levels,
- int groupsAtLevel,
- int countAtLeaf,
- ref int nextData)
- {
- var data = new AvaloniaList<object>();
- if (levels != 0)
- {
- for (int i = 0; i < groupsAtLevel; i++)
- {
- data.Add(CreateNestedData(levels - 1, groupsAtLevel, countAtLeaf, ref nextData));
- }
- }
- else
- {
- for (int i = 0; i < countAtLeaf; i++)
- {
- data.Add(nextData++);
- }
- }
- return data;
- }
- static IndexPath Path(params int[] path)
- {
- return IndexPath.CreateFromIndices(path);
- }
- private static int _nextData = 0;
- private struct TreeWalkNodeInfo
- {
- public object Current { get; set; }
- public IndexPath Path { get; set; }
- }
- private class ResettingList<T> : List<object>, INotifyCollectionChanged
- {
- public event NotifyCollectionChangedEventHandler CollectionChanged;
- public new void RemoveAt(int index)
- {
- var item = this[index];
- base.RemoveAt(index);
- CollectionChanged?.Invoke(
- this,
- new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, new[] { item }, index));
- }
- public void Reset(IEnumerable<object> items = null)
- {
- if (items != null)
- {
- Clear();
- AddRange(items);
- }
- CollectionChanged?.Invoke(
- this,
- new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
- }
- }
- }
- class CustomSelectionModel : SelectionModel
- {
- public int IntProperty
- {
- get { return _intProperty; }
- set
- {
- _intProperty = value;
- OnPropertyChanged("IntProperty");
- }
- }
- private int _intProperty;
- }
- }
|