TextBoxTests.cs 73 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252
  1. #nullable enable
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Reactive.Linq;
  5. using System.Threading.Tasks;
  6. using Avalonia.Controls.Presenters;
  7. using Avalonia.Controls.Primitives;
  8. using Avalonia.Controls.Templates;
  9. using Avalonia.Data;
  10. using Avalonia.Headless;
  11. using Avalonia.Input;
  12. using Avalonia.Input.Platform;
  13. using Avalonia.Input.TextInput;
  14. using Avalonia.Layout;
  15. using Avalonia.Media;
  16. using Avalonia.Platform;
  17. using Avalonia.UnitTests;
  18. using Avalonia.VisualTree;
  19. using Moq;
  20. using Xunit;
  21. namespace Avalonia.Controls.UnitTests
  22. {
  23. public class TextBoxTests : ScopedTestBase
  24. {
  25. [Fact]
  26. public void Opening_Context_Menu_Does_not_Lose_Selection()
  27. {
  28. using (UnitTestApplication.Start(FocusServices))
  29. {
  30. var target1 = new TextBox
  31. {
  32. Template = CreateTemplate(),
  33. Text = "1234",
  34. ContextMenu = new TestContextMenu()
  35. };
  36. var target2 = new TextBox
  37. {
  38. Template = CreateTemplate(),
  39. Text = "5678"
  40. };
  41. var sp = new StackPanel();
  42. sp.Children.Add(target1);
  43. sp.Children.Add(target2);
  44. target1.ApplyTemplate();
  45. target2.ApplyTemplate();
  46. var root = new TestRoot() { Child = sp };
  47. target1.SelectionStart = 0;
  48. target1.SelectionEnd = 3;
  49. target1.Focus();
  50. Assert.False(target2.IsFocused);
  51. Assert.True(target1.IsFocused);
  52. target2.Focus();
  53. Assert.Equal("123", target1.SelectedText);
  54. }
  55. }
  56. [Fact]
  57. public void TextBox_Should_Lose_Focus_When_Disabled()
  58. {
  59. using (UnitTestApplication.Start(FocusServices))
  60. {
  61. var target = new TextBox
  62. {
  63. Template = CreateTemplate()
  64. };
  65. target.ApplyTemplate();
  66. var root = new TestRoot() { Child = target };
  67. target.Focus();
  68. Assert.True(target.IsFocused);
  69. target.IsEnabled = false;
  70. Assert.False(target.IsFocused);
  71. Assert.False(target.IsEnabled);
  72. }
  73. }
  74. [Fact]
  75. public void Opening_Context_Flyout_Does_not_Lose_Selection()
  76. {
  77. using (UnitTestApplication.Start(FocusServices))
  78. {
  79. var target1 = new TextBox
  80. {
  81. Template = CreateTemplate(),
  82. Text = "1234",
  83. ContextFlyout = new MenuFlyout
  84. {
  85. Items =
  86. {
  87. new MenuItem { Header = "Item 1" },
  88. new MenuItem {Header = "Item 2" },
  89. new MenuItem {Header = "Item 3" }
  90. }
  91. }
  92. };
  93. target1.ApplyTemplate();
  94. var root = new TestRoot() { Child = target1 };
  95. target1.SelectionStart = 0;
  96. target1.SelectionEnd = 3;
  97. target1.Focus();
  98. Assert.True(target1.IsFocused);
  99. target1.ContextFlyout.ShowAt(target1);
  100. Assert.Equal("123", target1.SelectedText);
  101. }
  102. }
  103. [Fact]
  104. public void DefaultBindingMode_Should_Be_TwoWay()
  105. {
  106. Assert.Equal(
  107. BindingMode.TwoWay,
  108. TextBox.TextProperty.GetMetadata(typeof(TextBox)).DefaultBindingMode);
  109. }
  110. [Fact]
  111. public void TextBox_Ignore_Word_Move_In_Password_Field()
  112. {
  113. using (UnitTestApplication.Start(Services))
  114. {
  115. var target = new TextBox
  116. {
  117. Template = CreateTemplate(),
  118. PasswordChar = '*',
  119. Text = "passw0rd"
  120. };
  121. target.ApplyTemplate();
  122. target.Measure(Size.Infinity);
  123. target.CaretIndex = 8;
  124. RaiseKeyEvent(target, Key.Left, KeyModifiers.Control);
  125. Assert.Equal(7, target.CaretIndex);
  126. }
  127. }
  128. [Fact]
  129. public void CaretIndex_Can_Moved_To_Position_After_The_End_Of_Text_With_Arrow_Key()
  130. {
  131. using (UnitTestApplication.Start(Services))
  132. {
  133. var target = new TextBox
  134. {
  135. Template = CreateTemplate(),
  136. Text = "1234"
  137. };
  138. target.ApplyTemplate();
  139. target.Measure(Size.Infinity);
  140. target.CaretIndex = 3;
  141. RaiseKeyEvent(target, Key.Right, 0);
  142. Assert.Equal(4, target.CaretIndex);
  143. }
  144. }
  145. [Fact]
  146. public void Control_Backspace_Should_Set_Caret_Position_To_The_Start_Of_The_Deletion()
  147. {
  148. using (UnitTestApplication.Start(Services))
  149. {
  150. var target = new TextBox
  151. {
  152. Template = CreateTemplate(),
  153. Text = "First Second Third",
  154. SelectionStart = 13,
  155. SelectionEnd = 13
  156. };
  157. target.CaretIndex = 10;
  158. target.ApplyTemplate();
  159. // (First Second |Third)
  160. RaiseKeyEvent(target, Key.Back, KeyModifiers.Control);
  161. // (First |Third)
  162. Assert.Equal(6, target.CaretIndex);
  163. }
  164. }
  165. [Fact]
  166. public void Control_Backspace_Should_Remove_The_Double_Whitespace_If_Caret_Index_Was_At_The_End_Of_A_Word()
  167. {
  168. using (UnitTestApplication.Start(Services))
  169. {
  170. var target = new TextBox
  171. {
  172. Template = CreateTemplate(),
  173. Text = "First Second Third",
  174. SelectionStart = 12,
  175. SelectionEnd = 12
  176. };
  177. target.ApplyTemplate();
  178. // (First Second| Third)
  179. RaiseKeyEvent(target, Key.Back, KeyModifiers.Control);
  180. // (First| Third)
  181. Assert.Equal("First Third", target.Text);
  182. }
  183. }
  184. [Fact]
  185. public void Control_Backspace_Undo_Should_Return_Caret_Position()
  186. {
  187. using (UnitTestApplication.Start(Services))
  188. {
  189. var target = new TextBox
  190. {
  191. Template = CreateTemplate(),
  192. Text = "First Second Third",
  193. SelectionStart = 9,
  194. SelectionEnd = 9
  195. };
  196. target.ApplyTemplate();
  197. // (First Second| Third)
  198. RaiseKeyEvent(target, Key.Back, KeyModifiers.Control);
  199. // (First| Third)
  200. target.Undo();
  201. // (First Second| Third)
  202. Assert.Equal(9, target.CaretIndex);
  203. }
  204. }
  205. [Fact]
  206. public void Press_Ctrl_A_Select_All_Text()
  207. {
  208. using (UnitTestApplication.Start(Services))
  209. {
  210. var target = new TextBox
  211. {
  212. Template = CreateTemplate(),
  213. Text = "1234"
  214. };
  215. target.ApplyTemplate();
  216. RaiseKeyEvent(target, Key.A, KeyModifiers.Control);
  217. Assert.Equal(0, target.SelectionStart);
  218. Assert.Equal(4, target.SelectionEnd);
  219. }
  220. }
  221. [Fact]
  222. public void Press_Ctrl_A_Select_All_Null_Text()
  223. {
  224. using (UnitTestApplication.Start(Services))
  225. {
  226. var target = new TextBox
  227. {
  228. Template = CreateTemplate()
  229. };
  230. RaiseKeyEvent(target, Key.A, KeyModifiers.Control);
  231. Assert.Equal(0, target.SelectionStart);
  232. Assert.Equal(0, target.SelectionEnd);
  233. }
  234. }
  235. [Fact]
  236. public void Press_Ctrl_Z_Will_Not_Modify_Text()
  237. {
  238. using (UnitTestApplication.Start(Services))
  239. {
  240. var target = new TextBox
  241. {
  242. Template = CreateTemplate(),
  243. Text = "1234"
  244. };
  245. RaiseKeyEvent(target, Key.Z, KeyModifiers.Control);
  246. Assert.Equal("1234", target.Text);
  247. }
  248. }
  249. [Fact]
  250. public void Control_Backspace_Should_Remove_The_Word_Before_The_Caret_If_There_Is_No_Selection()
  251. {
  252. using (UnitTestApplication.Start(Services))
  253. {
  254. TextBox textBox = new TextBox
  255. {
  256. Template = CreateTemplate(),
  257. Text = "First Second Third Fourth",
  258. SelectionStart = 5,
  259. SelectionEnd = 5
  260. };
  261. textBox.ApplyTemplate();
  262. // (First| Second Third Fourth)
  263. RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
  264. Assert.Equal(" Second Third Fourth", textBox.Text);
  265. // ( Second |Third Fourth)
  266. textBox.CaretIndex = 8;
  267. RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
  268. Assert.Equal(" Third Fourth", textBox.Text);
  269. // ( Thi|rd Fourth)
  270. textBox.CaretIndex = 4;
  271. RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
  272. Assert.Equal(" rd Fourth", textBox.Text);
  273. // ( rd F[ou]rth)
  274. textBox.SelectionStart = 5;
  275. textBox.SelectionEnd = 7;
  276. RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
  277. Assert.Equal(" rd Frth", textBox.Text);
  278. // ( |rd Frth)
  279. textBox.CaretIndex = 1;
  280. RaiseKeyEvent(textBox, Key.Back, KeyModifiers.Control);
  281. Assert.Equal("rd Frth", textBox.Text);
  282. }
  283. }
  284. [Fact]
  285. public void Control_Delete_Should_Remove_The_Word_After_The_Caret_If_There_Is_No_Selection()
  286. {
  287. using (UnitTestApplication.Start(Services))
  288. {
  289. TextBox textBox = new TextBox
  290. {
  291. Template = CreateTemplate(),
  292. Text = "First Second Third Fourth",
  293. CaretIndex = 19,
  294. };
  295. textBox.ApplyTemplate();
  296. // (First Second Third |Fourth)
  297. RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
  298. Assert.Equal("First Second Third ", textBox.Text);
  299. // (First Second |Third )
  300. textBox.CaretIndex = 13;
  301. RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
  302. Assert.Equal("First Second ", textBox.Text);
  303. // (First Sec|ond )
  304. textBox.CaretIndex = 9;
  305. RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
  306. Assert.Equal("First Sec", textBox.Text);
  307. // (Fi[rs]t Sec )
  308. textBox.SelectionStart = 2;
  309. textBox.SelectionEnd = 4;
  310. RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
  311. Assert.Equal("Fit Sec", textBox.Text);
  312. // (Fit Sec| )
  313. textBox.Text += " ";
  314. textBox.CaretIndex = 7;
  315. RaiseKeyEvent(textBox, Key.Delete, KeyModifiers.Control);
  316. Assert.Equal("Fit Sec", textBox.Text);
  317. }
  318. }
  319. [Fact]
  320. public void Setting_SelectionStart_To_SelectionEnd_Sets_CaretPosition_To_SelectionStart()
  321. {
  322. using (UnitTestApplication.Start(Services))
  323. {
  324. var textBox = new TextBox
  325. {
  326. Text = "0123456789"
  327. };
  328. textBox.SelectionStart = 2;
  329. textBox.SelectionEnd = 2;
  330. Assert.Equal(2, textBox.CaretIndex);
  331. }
  332. }
  333. [Fact]
  334. public void Setting_Text_Updates_CaretPosition()
  335. {
  336. using (UnitTestApplication.Start(Services))
  337. {
  338. var target = new TextBox
  339. {
  340. Text = "Initial Text",
  341. CaretIndex = 11
  342. };
  343. var invoked = false;
  344. target.GetObservable(TextBox.TextProperty).Skip(1).Subscribe(_ =>
  345. {
  346. // Caret index should be set before Text changed notification, as we don't want
  347. // to notify with an invalid CaretIndex.
  348. Assert.Equal(7, target.CaretIndex);
  349. invoked = true;
  350. });
  351. target.Text = "Changed";
  352. Assert.True(invoked);
  353. }
  354. }
  355. [Fact]
  356. public void Press_Enter_Does_Not_Accept_Return()
  357. {
  358. using (UnitTestApplication.Start(Services))
  359. {
  360. var target = new TextBox
  361. {
  362. Template = CreateTemplate(),
  363. AcceptsReturn = false,
  364. Text = "1234"
  365. };
  366. target.ApplyTemplate();
  367. RaiseKeyEvent(target, Key.Enter, 0);
  368. Assert.Equal("1234", target.Text);
  369. }
  370. }
  371. [Fact]
  372. public void Press_Enter_Add_Default_Newline()
  373. {
  374. using (UnitTestApplication.Start(Services))
  375. {
  376. var target = new TextBox
  377. {
  378. Template = CreateTemplate(),
  379. AcceptsReturn = true
  380. };
  381. target.ApplyTemplate();
  382. RaiseKeyEvent(target, Key.Enter, 0);
  383. Assert.Equal(Environment.NewLine, target.Text);
  384. }
  385. }
  386. [Fact]
  387. public void Press_Enter_Add_Custom_Newline()
  388. {
  389. using (UnitTestApplication.Start(Services))
  390. {
  391. var target = new TextBox
  392. {
  393. Template = CreateTemplate(),
  394. AcceptsReturn = true,
  395. NewLine = "Test"
  396. };
  397. target.ApplyTemplate();
  398. RaiseKeyEvent(target, Key.Enter, 0);
  399. Assert.Equal("Test", target.Text);
  400. }
  401. }
  402. [Theory]
  403. [InlineData(new object[] { false, TextWrapping.NoWrap, ScrollBarVisibility.Hidden })]
  404. [InlineData(new object[] { false, TextWrapping.Wrap, ScrollBarVisibility.Disabled })]
  405. [InlineData(new object[] { true, TextWrapping.NoWrap, ScrollBarVisibility.Auto })]
  406. [InlineData(new object[] { true, TextWrapping.Wrap, ScrollBarVisibility.Disabled })]
  407. public void Has_Correct_Horizontal_ScrollBar_Visibility(
  408. bool acceptsReturn,
  409. TextWrapping wrapping,
  410. ScrollBarVisibility expected)
  411. {
  412. using (UnitTestApplication.Start(Services))
  413. {
  414. var target = new TextBox
  415. {
  416. AcceptsReturn = acceptsReturn,
  417. TextWrapping = wrapping,
  418. };
  419. Assert.Equal(expected, ScrollViewer.GetHorizontalScrollBarVisibility(target));
  420. }
  421. }
  422. [Fact]
  423. public void SelectionEnd_Doesnt_Cause_Exception()
  424. {
  425. using (UnitTestApplication.Start(Services))
  426. {
  427. var target = new TextBox
  428. {
  429. Template = CreateTemplate(),
  430. Text = "0123456789"
  431. };
  432. target.ApplyTemplate();
  433. target.SelectionStart = 0;
  434. target.SelectionEnd = 9;
  435. target.Text = "123";
  436. RaiseTextEvent(target, "456");
  437. Assert.True(true);
  438. }
  439. }
  440. [Fact]
  441. public void SelectionStart_Doesnt_Cause_Exception()
  442. {
  443. using (UnitTestApplication.Start(Services))
  444. {
  445. var target = new TextBox
  446. {
  447. Template = CreateTemplate(),
  448. Text = "0123456789"
  449. };
  450. target.ApplyTemplate();
  451. target.SelectionStart = 8;
  452. target.SelectionEnd = 9;
  453. target.Text = "123";
  454. RaiseTextEvent(target, "456");
  455. Assert.True(true);
  456. }
  457. }
  458. [Fact]
  459. public void SelectionStartEnd_Are_Valid_AterTextChange()
  460. {
  461. using (UnitTestApplication.Start(Services))
  462. {
  463. var target = new TextBox
  464. {
  465. Template = CreateTemplate(),
  466. Text = "0123456789"
  467. };
  468. target.SelectionStart = 8;
  469. target.SelectionEnd = 9;
  470. target.Text = "123";
  471. Assert.True(target.SelectionStart <= "123".Length);
  472. Assert.True(target.SelectionEnd <= "123".Length);
  473. }
  474. }
  475. [Fact]
  476. public void SelectedText_Changes_OnSelectionChange()
  477. {
  478. using (UnitTestApplication.Start(Services))
  479. {
  480. var target = new TextBox
  481. {
  482. Template = CreateTemplate(),
  483. Text = "0123456789"
  484. };
  485. target.ApplyTemplate();
  486. Assert.True(target.SelectedText == "");
  487. target.SelectionStart = 2;
  488. target.SelectionEnd = 4;
  489. Assert.True(target.SelectedText == "23");
  490. }
  491. }
  492. [Fact]
  493. public void SelectedText_EditsText()
  494. {
  495. using (UnitTestApplication.Start(Services))
  496. {
  497. var target = new TextBox
  498. {
  499. Template = CreateTemplate(),
  500. Text = "0123"
  501. };
  502. target.ApplyTemplate();
  503. target.SelectedText = "AA";
  504. Assert.True(target.Text == "AA0123");
  505. target.SelectionStart = 1;
  506. target.SelectionEnd = 3;
  507. target.SelectedText = "BB";
  508. Assert.True(target.Text == "ABB123");
  509. }
  510. }
  511. [Fact]
  512. public void SelectedText_CanClearText()
  513. {
  514. using (UnitTestApplication.Start(Services))
  515. {
  516. var target = new TextBox
  517. {
  518. Template = CreateTemplate(),
  519. Text = "0123"
  520. };
  521. target.SelectionStart = 1;
  522. target.SelectionEnd = 3;
  523. target.SelectedText = "";
  524. Assert.True(target.Text == "03");
  525. }
  526. }
  527. [Fact]
  528. public void SelectedText_NullClearsText()
  529. {
  530. using (UnitTestApplication.Start(Services))
  531. {
  532. var target = new TextBox
  533. {
  534. Template = CreateTemplate(),
  535. Text = "0123"
  536. };
  537. target.SelectionStart = 1;
  538. target.SelectionEnd = 3;
  539. target.SelectedText = null;
  540. Assert.True(target.Text == "03");
  541. }
  542. }
  543. [Fact]
  544. public void CoerceCaretIndex_Doesnt_Cause_Exception_with_malformed_line_ending()
  545. {
  546. using (UnitTestApplication.Start(Services))
  547. {
  548. var target = new TextBox
  549. {
  550. Template = CreateTemplate(),
  551. Text = "0123456789\r"
  552. };
  553. target.CaretIndex = 11;
  554. Assert.True(true);
  555. }
  556. }
  557. [Theory]
  558. [InlineData(Key.Up)]
  559. [InlineData(Key.Down)]
  560. [InlineData(Key.Home)]
  561. [InlineData(Key.End)]
  562. public void Textbox_doesnt_crash_when_Receives_input_and_template_not_applied(Key key)
  563. {
  564. using (UnitTestApplication.Start(FocusServices))
  565. {
  566. var target1 = new TextBox
  567. {
  568. Template = CreateTemplate(),
  569. Text = "1234",
  570. };
  571. var root = new TestRoot { Child = target1 };
  572. target1.Focus();
  573. Assert.True(target1.IsFocused);
  574. RaiseKeyEvent(target1, key, KeyModifiers.None);
  575. }
  576. }
  577. [Fact]
  578. public void TextBox_GotFocus_And_LostFocus_Work_Properly()
  579. {
  580. using (UnitTestApplication.Start(FocusServices))
  581. {
  582. var target1 = new TextBox
  583. {
  584. Template = CreateTemplate(),
  585. Text = "1234"
  586. };
  587. var target2 = new TextBox
  588. {
  589. Template = CreateTemplate(),
  590. Text = "5678"
  591. };
  592. var sp = new StackPanel();
  593. sp.Children.Add(target1);
  594. sp.Children.Add(target2);
  595. target1.ApplyTemplate();
  596. target2.ApplyTemplate();
  597. var root = new TestRoot { Child = sp };
  598. var gfcount = 0;
  599. var lfcount = 0;
  600. target1.GotFocus += (s, e) => gfcount++;
  601. target2.LostFocus += (s, e) => lfcount++;
  602. target2.Focus();
  603. Assert.False(target1.IsFocused);
  604. Assert.True(target2.IsFocused);
  605. target1.Focus();
  606. Assert.False(target2.IsFocused);
  607. Assert.True(target1.IsFocused);
  608. Assert.Equal(1, gfcount);
  609. Assert.Equal(1, lfcount);
  610. }
  611. }
  612. [Fact]
  613. public void TextBox_CaretIndex_Persists_When_Focus_Lost()
  614. {
  615. using (UnitTestApplication.Start(FocusServices))
  616. {
  617. var target1 = new TextBox
  618. {
  619. Template = CreateTemplate(),
  620. Text = "1234"
  621. };
  622. var target2 = new TextBox
  623. {
  624. Template = CreateTemplate(),
  625. Text = "5678"
  626. };
  627. var sp = new StackPanel();
  628. sp.Children.Add(target1);
  629. sp.Children.Add(target2);
  630. target1.ApplyTemplate();
  631. target2.ApplyTemplate();
  632. var root = new TestRoot { Child = sp };
  633. target2.Focus();
  634. target2.CaretIndex = 2;
  635. Assert.False(target1.IsFocused);
  636. Assert.True(target2.IsFocused);
  637. target1.Focus();
  638. Assert.Equal(2, target2.CaretIndex);
  639. }
  640. }
  641. [Fact]
  642. public void TextBox_Reveal_Password_Reset_When_Lost_Focus()
  643. {
  644. using (UnitTestApplication.Start(FocusServices))
  645. {
  646. var target1 = new TextBox
  647. {
  648. Template = CreateTemplate(),
  649. Text = "1234",
  650. PasswordChar = '*'
  651. };
  652. var target2 = new TextBox
  653. {
  654. Template = CreateTemplate(),
  655. Text = "5678"
  656. };
  657. var sp = new StackPanel();
  658. sp.Children.Add(target1);
  659. sp.Children.Add(target2);
  660. target1.ApplyTemplate();
  661. target2.ApplyTemplate();
  662. var root = new TestRoot { Child = sp };
  663. target1.Focus();
  664. target1.RevealPassword = true;
  665. target2.Focus();
  666. Assert.False(target1.RevealPassword);
  667. }
  668. }
  669. [Fact]
  670. public void Setting_Bound_Text_To_Null_Works()
  671. {
  672. using (UnitTestApplication.Start(Services))
  673. {
  674. var source = new Class1 { Bar = "bar" };
  675. var target = new TextBox { Template = CreateTemplate(), DataContext = source };
  676. target.ApplyTemplate();
  677. target.Bind(TextBox.TextProperty, new Binding("Bar"));
  678. Assert.Equal("bar", target.Text);
  679. source.Bar = null;
  680. Assert.Null(target.Text);
  681. }
  682. }
  683. [Theory]
  684. [InlineData("abc", "d", 3, 0, 0, false, "abc")]
  685. [InlineData("abc", "dd", 4, 3, 3, false, "abcd")]
  686. [InlineData("abc", "ddd", 3, 0, 2, true, "ddc")]
  687. [InlineData("abc", "dddd", 4, 1, 3, true, "addd")]
  688. [InlineData("abc", "ddddd", 5, 3, 3, true, "abcdd")]
  689. public async Task MaxLength_Works_Properly(
  690. string initalText,
  691. string textInput,
  692. int maxLength,
  693. int selectionStart,
  694. int selectionEnd,
  695. bool fromClipboard,
  696. string expected)
  697. {
  698. using (UnitTestApplication.Start(Services))
  699. {
  700. var target = new TextBox
  701. {
  702. Template = CreateTemplate(),
  703. Text = initalText,
  704. MaxLength = maxLength,
  705. SelectionStart = selectionStart,
  706. SelectionEnd = selectionEnd
  707. };
  708. var impl = CreateMockTopLevelImpl();
  709. var topLevel = new TestTopLevel(impl.Object)
  710. {
  711. Template = CreateTopLevelTemplate()
  712. };
  713. topLevel.Content = target;
  714. topLevel.ApplyTemplate();
  715. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  716. target.Measure(Size.Infinity);
  717. if (fromClipboard)
  718. {
  719. await topLevel.Clipboard!.SetTextAsync(textInput);
  720. RaiseKeyEvent(target, Key.V, KeyModifiers.Control);
  721. await topLevel.Clipboard!.ClearAsync();
  722. }
  723. else
  724. {
  725. RaiseTextEvent(target, textInput);
  726. }
  727. Assert.Equal(expected, target.Text);
  728. }
  729. }
  730. [Theory]
  731. [InlineData(Key.X, KeyModifiers.Control)]
  732. [InlineData(Key.Back, KeyModifiers.None)]
  733. [InlineData(Key.Delete, KeyModifiers.None)]
  734. [InlineData(Key.Tab, KeyModifiers.None)]
  735. [InlineData(Key.Enter, KeyModifiers.None)]
  736. public void Keys_Allow_Undo(Key key, KeyModifiers modifiers)
  737. {
  738. using (UnitTestApplication.Start(Services))
  739. {
  740. var target = new TextBox
  741. {
  742. Template = CreateTemplate(),
  743. Text = "0123",
  744. AcceptsReturn = true,
  745. AcceptsTab = true
  746. };
  747. var impl = CreateMockTopLevelImpl();
  748. var topLevel = new TestTopLevel(impl.Object)
  749. {
  750. Template = CreateTopLevelTemplate()
  751. };
  752. topLevel.Content = target;
  753. topLevel.ApplyTemplate();
  754. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  755. target.ApplyTemplate();
  756. target.SelectionStart = 1;
  757. target.SelectionEnd = 3;
  758. RaiseKeyEvent(target, key, modifiers);
  759. RaiseKeyEvent(target, Key.Z, KeyModifiers.Control); // undo
  760. Assert.True(target.Text == "0123");
  761. }
  762. }
  763. [Fact]
  764. public void Setting_SelectedText_Should_Fire_Single_Text_Changed_Notification()
  765. {
  766. using (UnitTestApplication.Start(Services))
  767. {
  768. var target = new TextBox
  769. {
  770. Template = CreateTemplate(),
  771. Text = "0123",
  772. AcceptsReturn = true,
  773. AcceptsTab = true,
  774. SelectionStart = 1,
  775. SelectionEnd = 3,
  776. };
  777. var values = new List<string?>();
  778. target.GetObservable(TextBox.TextProperty).Subscribe(x => values.Add(x));
  779. target.SelectedText = "A";
  780. Assert.Equal(new[] { "0123", "0A3" }, values);
  781. }
  782. }
  783. [Fact]
  784. public void Entering_Text_With_SelectedText_Should_Fire_Single_Text_Changed_Notification()
  785. {
  786. using (UnitTestApplication.Start(Services))
  787. {
  788. var target = new TextBox
  789. {
  790. Template = CreateTemplate(),
  791. Text = "0123",
  792. AcceptsReturn = true,
  793. AcceptsTab = true,
  794. SelectionStart = 1,
  795. SelectionEnd = 3,
  796. };
  797. var values = new List<string?>();
  798. target.GetObservable(TextBox.TextProperty).Subscribe(x => values.Add(x));
  799. RaiseTextEvent(target, "A");
  800. Assert.Equal(new[] { "0123", "0A3" }, values);
  801. }
  802. }
  803. [Fact]
  804. public void Insert_Multiline_Text_Should_Accept_Extra_Lines_When_AcceptsReturn_Is_True()
  805. {
  806. using (UnitTestApplication.Start(Services))
  807. {
  808. var target = new TextBox
  809. {
  810. AcceptsReturn = true
  811. };
  812. RaiseTextEvent(target, $"123 {Environment.NewLine}456");
  813. Assert.Equal($"123 {Environment.NewLine}456", target.Text);
  814. }
  815. }
  816. [Fact]
  817. public void Insert_Multiline_Text_Should_Discard_Extra_Lines_When_AcceptsReturn_Is_False()
  818. {
  819. using (UnitTestApplication.Start(Services))
  820. {
  821. var target = new TextBox
  822. {
  823. AcceptsReturn = false
  824. };
  825. RaiseTextEvent(target, $"123 {"\r"}456");
  826. Assert.Equal("123 ", target.Text);
  827. target.Text = "";
  828. RaiseTextEvent(target, $"123 {"\r\n"}456");
  829. Assert.Equal("123 ", target.Text);
  830. }
  831. }
  832. [Fact]
  833. public async Task Should_Fullfill_MaxLines_Contraint()
  834. {
  835. using (UnitTestApplication.Start(Services))
  836. {
  837. var target = new TextBox
  838. {
  839. Template = CreateTemplate(),
  840. Text = "ABC",
  841. MaxLines = 1,
  842. AcceptsReturn = true
  843. };
  844. var impl = CreateMockTopLevelImpl();
  845. var topLevel = new TestTopLevel(impl.Object)
  846. {
  847. Template = CreateTopLevelTemplate()
  848. };
  849. topLevel.Content = target;
  850. topLevel.ApplyTemplate();
  851. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  852. target.ApplyTemplate();
  853. target.Measure(Size.Infinity);
  854. var initialHeight = target.DesiredSize.Height;
  855. await topLevel.Clipboard!.SetTextAsync(Environment.NewLine);
  856. RaiseKeyEvent(target, Key.V, KeyModifiers.Control);
  857. await topLevel.Clipboard!.ClearAsync();
  858. RaiseTextEvent(target, Environment.NewLine);
  859. target.InvalidateMeasure();
  860. target.Measure(Size.Infinity);
  861. Assert.Equal(initialHeight, target.DesiredSize.Height);
  862. }
  863. }
  864. [Theory]
  865. [InlineData(1)]
  866. [InlineData(2)]
  867. [InlineData(3)]
  868. public void MaxLines_Sets_ScrollViewer_MaxHeight(int maxLines)
  869. {
  870. using (UnitTestApplication.Start(Services))
  871. {
  872. var target = new TextBox
  873. {
  874. Template = CreateTemplate(),
  875. MaxLines = maxLines,
  876. // Define explicit whole number line height for predictable calculations
  877. LineHeight = 20
  878. };
  879. var impl = CreateMockTopLevelImpl();
  880. var topLevel = new TestTopLevel(impl.Object)
  881. {
  882. Template = CreateTopLevelTemplate(),
  883. Content = target
  884. };
  885. topLevel.ApplyTemplate();
  886. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  887. var textPresenter = target.FindDescendantOfType<TextPresenter>();
  888. Assert.NotNull(textPresenter);
  889. Assert.Equal("PART_TextPresenter", textPresenter.Name);
  890. Assert.Equal(new Thickness(0), textPresenter.Margin); // Test assumes no margin on TextPresenter
  891. var scrollViewer = target.FindDescendantOfType<ScrollViewer>();
  892. Assert.NotNull(scrollViewer);
  893. Assert.Equal("PART_ScrollViewer", scrollViewer.Name);
  894. Assert.Equal(maxLines * target.LineHeight, scrollViewer.MaxHeight);
  895. }
  896. }
  897. [Theory]
  898. [InlineData(1)]
  899. [InlineData(2)]
  900. [InlineData(3)]
  901. public void MaxLines_Sets_ScrollViewer_MaxHeight_With_TextPresenter_Margin(int maxLines)
  902. {
  903. using (UnitTestApplication.Start(Services))
  904. {
  905. var target = new TextBox
  906. {
  907. Template = CreateTemplate(),
  908. MaxLines = maxLines,
  909. // Define explicit whole number line height for predictable calculations
  910. LineHeight = 20
  911. };
  912. var impl = CreateMockTopLevelImpl();
  913. var topLevel = new TestTopLevel(impl.Object)
  914. {
  915. Template = CreateTopLevelTemplate(),
  916. Content = target
  917. };
  918. topLevel.ApplyTemplate();
  919. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  920. var textPresenter = target.FindDescendantOfType<TextPresenter>();
  921. Assert.NotNull(textPresenter);
  922. Assert.Equal("PART_TextPresenter", textPresenter.Name);
  923. var textPresenterMargin = new Thickness(horizontal: 0, vertical: 3);
  924. textPresenter.Margin = textPresenterMargin;
  925. target.InvalidateMeasure();
  926. target.Measure(Size.Infinity);
  927. var scrollViewer = target.FindDescendantOfType<ScrollViewer>();
  928. Assert.NotNull(scrollViewer);
  929. Assert.Equal("PART_ScrollViewer", scrollViewer.Name);
  930. Assert.Equal((maxLines * target.LineHeight) + textPresenterMargin.Top + textPresenterMargin.Bottom, scrollViewer.MaxHeight);
  931. }
  932. }
  933. [Fact]
  934. public void Should_Fullfill_MinLines_Contraint()
  935. {
  936. using (UnitTestApplication.Start(Services))
  937. {
  938. var target = new TextBox
  939. {
  940. Template = CreateTemplate(),
  941. Text = "ABC \n DEF \n GHI",
  942. MinLines = 3,
  943. AcceptsReturn = true
  944. };
  945. var impl = CreateMockTopLevelImpl();
  946. var topLevel = new TestTopLevel(impl.Object)
  947. {
  948. Template = CreateTopLevelTemplate()
  949. };
  950. topLevel.Content = target;
  951. topLevel.ApplyTemplate();
  952. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  953. target.ApplyTemplate();
  954. target.Measure(Size.Infinity);
  955. var initialHeight = target.DesiredSize.Height;
  956. target.Text = "";
  957. target.InvalidateMeasure();
  958. target.Measure(Size.Infinity);
  959. Assert.Equal(initialHeight, target.DesiredSize.Height);
  960. }
  961. }
  962. [Theory]
  963. [InlineData(1)]
  964. [InlineData(2)]
  965. [InlineData(3)]
  966. public void MinLines_Sets_ScrollViewer_MinHeight(int minLines)
  967. {
  968. using (UnitTestApplication.Start(Services))
  969. {
  970. var target = new TextBox
  971. {
  972. Template = CreateTemplate(),
  973. MinLines = minLines,
  974. // Define explicit whole number line height for predictable calculations
  975. LineHeight = 20
  976. };
  977. var impl = CreateMockTopLevelImpl();
  978. var topLevel = new TestTopLevel(impl.Object)
  979. {
  980. Template = CreateTopLevelTemplate(),
  981. Content = target
  982. };
  983. topLevel.ApplyTemplate();
  984. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  985. var textPresenter = target.FindDescendantOfType<TextPresenter>();
  986. Assert.NotNull(textPresenter);
  987. Assert.Equal("PART_TextPresenter", textPresenter.Name);
  988. Assert.Equal(new Thickness(0), textPresenter.Margin); // Test assumes no margin on TextPresenter
  989. var scrollViewer = target.FindDescendantOfType<ScrollViewer>();
  990. Assert.NotNull(scrollViewer);
  991. Assert.Equal("PART_ScrollViewer", scrollViewer.Name);
  992. Assert.Equal(minLines * target.LineHeight, scrollViewer.MinHeight);
  993. }
  994. }
  995. [Theory]
  996. [InlineData(1)]
  997. [InlineData(2)]
  998. [InlineData(3)]
  999. public void MinLines_Sets_ScrollViewer_MinHeight_With_TextPresenter_Margin(int minLines)
  1000. {
  1001. using (UnitTestApplication.Start(Services))
  1002. {
  1003. var target = new TextBox
  1004. {
  1005. Template = CreateTemplate(),
  1006. MinLines = minLines,
  1007. // Define explicit whole number line height for predictable calculations
  1008. LineHeight = 20
  1009. };
  1010. var impl = CreateMockTopLevelImpl();
  1011. var topLevel = new TestTopLevel(impl.Object)
  1012. {
  1013. Template = CreateTopLevelTemplate(),
  1014. Content = target
  1015. };
  1016. topLevel.ApplyTemplate();
  1017. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  1018. var textPresenter = target.FindDescendantOfType<TextPresenter>();
  1019. Assert.NotNull(textPresenter);
  1020. Assert.Equal("PART_TextPresenter", textPresenter.Name);
  1021. var textPresenterMargin = new Thickness(horizontal: 0, vertical: 3);
  1022. textPresenter.Margin = textPresenterMargin;
  1023. target.InvalidateMeasure();
  1024. target.Measure(Size.Infinity);
  1025. var scrollViewer = target.FindDescendantOfType<ScrollViewer>();
  1026. Assert.NotNull(scrollViewer);
  1027. Assert.Equal("PART_ScrollViewer", scrollViewer.Name);
  1028. Assert.Equal((minLines * target.LineHeight) + textPresenterMargin.Top + textPresenterMargin.Bottom, scrollViewer.MinHeight);
  1029. }
  1030. }
  1031. [Theory]
  1032. [InlineData(null, 1)]
  1033. [InlineData("", 1)]
  1034. [InlineData("Hello", 1)]
  1035. [InlineData("Hello\r\nWorld", 2)]
  1036. public void LineCount_Is_Correct(string? text, int lineCount)
  1037. {
  1038. using (UnitTestApplication.Start(Services))
  1039. {
  1040. var target = new TextBox
  1041. {
  1042. Template = CreateTemplate(),
  1043. Text = text,
  1044. AcceptsReturn = true
  1045. };
  1046. var impl = CreateMockTopLevelImpl();
  1047. var topLevel = new TestTopLevel(impl.Object)
  1048. {
  1049. Template = CreateTopLevelTemplate()
  1050. };
  1051. topLevel.Content = target;
  1052. topLevel.ApplyTemplate();
  1053. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  1054. target.ApplyTemplate();
  1055. target.Measure(Size.Infinity);
  1056. Assert.Equal(lineCount, target.GetLineCount());
  1057. }
  1058. }
  1059. [Fact]
  1060. public void Unmeasured_TextBox_Has_Negative_LineCount()
  1061. {
  1062. var b = new TextBox();
  1063. Assert.Equal(-1, b.GetLineCount());
  1064. }
  1065. [Fact]
  1066. public void LineCount_Is_Correct_After_Text_Change()
  1067. {
  1068. using (UnitTestApplication.Start(Services))
  1069. {
  1070. var target = new TextBox
  1071. {
  1072. Template = CreateTemplate(),
  1073. Text = "Hello",
  1074. AcceptsReturn = true
  1075. };
  1076. var impl = CreateMockTopLevelImpl();
  1077. var topLevel = new TestTopLevel(impl.Object)
  1078. {
  1079. Template = CreateTopLevelTemplate()
  1080. };
  1081. topLevel.Content = target;
  1082. topLevel.ApplyTemplate();
  1083. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  1084. target.ApplyTemplate();
  1085. target.Measure(Size.Infinity);
  1086. Assert.Equal(1, target.GetLineCount());
  1087. target.Text = "Hello\r\nWorld";
  1088. Assert.Equal(2, target.GetLineCount());
  1089. }
  1090. }
  1091. [Fact]
  1092. public void Visible_LineCount_DoesNot_Affect_LineCount()
  1093. {
  1094. using (UnitTestApplication.Start(Services))
  1095. {
  1096. var target = new TextBox
  1097. {
  1098. Template = CreateTemplate(),
  1099. Text = "Hello\r\nWorld\r\nHello\r\nAvalonia",
  1100. AcceptsReturn = true,
  1101. MaxLines = 2,
  1102. };
  1103. var impl = CreateMockTopLevelImpl();
  1104. var topLevel = new TestTopLevel(impl.Object)
  1105. {
  1106. Template = CreateTopLevelTemplate()
  1107. };
  1108. topLevel.Content = target;
  1109. topLevel.ApplyTemplate();
  1110. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  1111. target.ApplyTemplate();
  1112. target.Measure(Size.Infinity);
  1113. Assert.Equal(4, target.GetLineCount());
  1114. }
  1115. }
  1116. [Fact]
  1117. public void CanUndo_CanRedo_Is_False_When_Initialized()
  1118. {
  1119. using (UnitTestApplication.Start(Services))
  1120. {
  1121. var tb = new TextBox
  1122. {
  1123. Template = CreateTemplate(),
  1124. Text = "New Text"
  1125. };
  1126. tb.Measure(Size.Infinity);
  1127. Assert.False(tb.CanUndo);
  1128. Assert.False(tb.CanRedo);
  1129. }
  1130. }
  1131. [Fact]
  1132. public void CanUndo_CanRedo_and_Programmatic_Undo_Redo_Works()
  1133. {
  1134. using (UnitTestApplication.Start(Services))
  1135. {
  1136. var tb = new TextBox
  1137. {
  1138. Template = CreateTemplate(),
  1139. };
  1140. tb.Measure(Size.Infinity);
  1141. // See GH #6024 for a bit more insight on when Undo/Redo snapshots are taken:
  1142. // - Every 'Space', but only when space is handled in OnKeyDown - Spaces in TextInput event won't work
  1143. // - Every 7 chars in a long word
  1144. RaiseTextEvent(tb, "ABC");
  1145. RaiseKeyEvent(tb, Key.Space, KeyModifiers.None);
  1146. RaiseTextEvent(tb, "DEF");
  1147. RaiseKeyEvent(tb, Key.Space, KeyModifiers.None);
  1148. RaiseTextEvent(tb, "123");
  1149. // NOTE: the spaces won't actually add spaces b/c they're sent only as key events and not Text events
  1150. // so our final text is without spaces
  1151. Assert.Equal("ABCDEF123", tb.Text);
  1152. Assert.True(tb.CanUndo);
  1153. tb.Undo();
  1154. // Undo will take us back one step
  1155. Assert.Equal("ABCDEF", tb.Text);
  1156. Assert.True(tb.CanRedo);
  1157. tb.Redo();
  1158. // Redo should restore us
  1159. Assert.Equal("ABCDEF123", tb.Text);
  1160. }
  1161. }
  1162. [Fact]
  1163. public void Setting_UndoLimit_Clears_Undo_Redo()
  1164. {
  1165. using (UnitTestApplication.Start(Services))
  1166. {
  1167. var tb = new TextBox
  1168. {
  1169. Template = CreateTemplate(),
  1170. };
  1171. tb.Measure(Size.Infinity);
  1172. // This is all the same as the above test (CanUndo_CanRedo_and_Programmatic_Undo_Redo_Works)
  1173. // We do this to get the undo/redo stacks in a state where both are active
  1174. RaiseTextEvent(tb, "ABC");
  1175. RaiseKeyEvent(tb, Key.Space, KeyModifiers.None);
  1176. RaiseTextEvent(tb, "DEF");
  1177. RaiseKeyEvent(tb, Key.Space, KeyModifiers.None);
  1178. RaiseTextEvent(tb, "123");
  1179. Assert.Equal("ABCDEF123", tb.Text);
  1180. Assert.True(tb.CanUndo);
  1181. tb.Undo();
  1182. // Undo will take us back one step
  1183. Assert.Equal("ABCDEF", tb.Text);
  1184. Assert.True(tb.CanRedo);
  1185. tb.Redo();
  1186. // Redo should restore us
  1187. Assert.Equal("ABCDEF123", tb.Text);
  1188. // Change the undo limit, this should clear both stacks setting CanUndo and CanRedo to false
  1189. tb.UndoLimit = 1;
  1190. Assert.False(tb.CanUndo);
  1191. Assert.False(tb.CanRedo);
  1192. }
  1193. }
  1194. [Fact]
  1195. public void Setting_IsUndoEnabled_To_False_Clears_Undo_Redo()
  1196. {
  1197. using (UnitTestApplication.Start(Services))
  1198. {
  1199. var tb = new TextBox
  1200. {
  1201. Template = CreateTemplate(),
  1202. };
  1203. tb.Measure(Size.Infinity);
  1204. // This is all the same as the above test (CanUndo_CanRedo_and_Programmatic_Undo_Redo_Works)
  1205. // We do this to get the undo/redo stacks in a state where both are active
  1206. RaiseTextEvent(tb, "ABC");
  1207. RaiseKeyEvent(tb, Key.Space, KeyModifiers.None);
  1208. RaiseTextEvent(tb, "DEF");
  1209. RaiseKeyEvent(tb, Key.Space, KeyModifiers.None);
  1210. RaiseTextEvent(tb, "123");
  1211. Assert.Equal("ABCDEF123", tb.Text);
  1212. Assert.True(tb.CanUndo);
  1213. tb.Undo();
  1214. // Undo will take us back one step
  1215. Assert.Equal("ABCDEF", tb.Text);
  1216. Assert.True(tb.CanRedo);
  1217. tb.Redo();
  1218. // Redo should restore us
  1219. Assert.Equal("ABCDEF123", tb.Text);
  1220. // Disable Undo/Redo, this should clear both stacks setting CanUndo and CanRedo to false
  1221. tb.IsUndoEnabled = false;
  1222. Assert.False(tb.CanUndo);
  1223. Assert.False(tb.CanRedo);
  1224. }
  1225. }
  1226. [Fact]
  1227. public void UndoLimit_Count_Is_Respected()
  1228. {
  1229. using (UnitTestApplication.Start(Services))
  1230. {
  1231. var tb = new TextBox
  1232. {
  1233. Template = CreateTemplate(),
  1234. UndoLimit = 3 // Something small for this test
  1235. };
  1236. tb.Measure(Size.Infinity);
  1237. // Push 3 undoable actions, we should only be able to recover 2
  1238. RaiseTextEvent(tb, "ABC");
  1239. RaiseKeyEvent(tb, Key.Space, KeyModifiers.None);
  1240. RaiseTextEvent(tb, "DEF");
  1241. RaiseKeyEvent(tb, Key.Space, KeyModifiers.None);
  1242. RaiseTextEvent(tb, "123");
  1243. Assert.Equal("ABCDEF123", tb.Text);
  1244. // Undo will take us back one step
  1245. tb.Undo();
  1246. Assert.Equal("ABCDEF", tb.Text);
  1247. // Undo again
  1248. tb.Undo();
  1249. Assert.Equal("ABC", tb.Text);
  1250. // We now should not be able to undo again
  1251. Assert.False(tb.CanUndo);
  1252. }
  1253. }
  1254. [Fact]
  1255. public void Should_Move_Caret_To_EndOfLine()
  1256. {
  1257. using (UnitTestApplication.Start(Services))
  1258. {
  1259. var tb = new TextBox
  1260. {
  1261. Template = CreateTemplate(),
  1262. Text = "AB\nAB"
  1263. };
  1264. tb.Measure(Size.Infinity);
  1265. RaiseKeyEvent(tb, Key.End, KeyModifiers.Shift);
  1266. Assert.Equal(2, tb.CaretIndex);
  1267. }
  1268. }
  1269. [Theory]
  1270. [InlineData(2,4)]
  1271. [InlineData(0,4)]
  1272. [InlineData(2,6)]
  1273. [InlineData(0,6)]
  1274. [InlineData(3,4)]
  1275. public void When_Selection_From_Left_To_Right_Pressing_Right_Should_Remove_Selection_Moving_Caret_To_End_Of_Previous_Selection(int selectionStart, int selectionEnd)
  1276. {
  1277. using (UnitTestApplication.Start(Services))
  1278. {
  1279. var tb = new TextBox
  1280. {
  1281. Template = CreateTemplate(),
  1282. Text = "ABCDEF"
  1283. };
  1284. tb.Measure(Size.Infinity);
  1285. tb.CaretIndex = selectionStart;
  1286. tb.SelectionStart = selectionStart;
  1287. tb.SelectionEnd = selectionEnd;
  1288. RaiseKeyEvent(tb, Key.Right, KeyModifiers.None);
  1289. Assert.Equal(selectionEnd, tb.SelectionStart);
  1290. Assert.Equal(selectionEnd, tb.SelectionEnd);
  1291. Assert.Equal(selectionEnd, tb.CaretIndex);
  1292. }
  1293. }
  1294. [Theory]
  1295. [InlineData(2,4)]
  1296. [InlineData(0,4)]
  1297. [InlineData(2,6)]
  1298. [InlineData(0,6)]
  1299. [InlineData(3,4)]
  1300. public void When_Selection_From_Left_To_Right_Pressing_Left_Should_Remove_Selection_Moving_Caret_To_Start_Of_Previous_Selection(int selectionStart, int selectionEnd)
  1301. {
  1302. using (UnitTestApplication.Start(Services))
  1303. {
  1304. var tb = new TextBox
  1305. {
  1306. Template = CreateTemplate(),
  1307. Text = "ABCDEF"
  1308. };
  1309. tb.Measure(Size.Infinity);
  1310. tb.CaretIndex = selectionStart;
  1311. tb.SelectionStart = selectionStart;
  1312. tb.SelectionEnd = selectionEnd;
  1313. RaiseKeyEvent(tb, Key.Left, KeyModifiers.None);
  1314. Assert.Equal(selectionStart, tb.SelectionStart);
  1315. Assert.Equal(selectionStart, tb.SelectionEnd);
  1316. Assert.Equal(selectionStart, tb.CaretIndex);
  1317. }
  1318. }
  1319. [Theory]
  1320. [InlineData(4,2)]
  1321. [InlineData(4,0)]
  1322. [InlineData(6,2)]
  1323. [InlineData(6,0)]
  1324. [InlineData(4,3)]
  1325. public void When_Selection_From_Right_To_Left_Pressing_Right_Should_Remove_Selection_Moving_Caret_To_Start_Of_Previous_Selection(int selectionStart, int selectionEnd)
  1326. {
  1327. using (UnitTestApplication.Start(Services))
  1328. {
  1329. var tb = new TextBox
  1330. {
  1331. Template = CreateTemplate(),
  1332. Text = "ABCDEF"
  1333. };
  1334. tb.Measure(Size.Infinity);
  1335. tb.CaretIndex = selectionStart;
  1336. tb.SelectionStart = selectionStart;
  1337. tb.SelectionEnd = selectionEnd;
  1338. RaiseKeyEvent(tb, Key.Right, KeyModifiers.None);
  1339. Assert.Equal(selectionStart, tb.SelectionStart);
  1340. Assert.Equal(selectionStart, tb.SelectionEnd);
  1341. Assert.Equal(selectionStart, tb.CaretIndex);
  1342. }
  1343. }
  1344. [Theory]
  1345. [InlineData(4,2)]
  1346. [InlineData(4,0)]
  1347. [InlineData(6,2)]
  1348. [InlineData(6,0)]
  1349. [InlineData(4,3)]
  1350. public void When_Selection_From_Right_To_Left_Pressing_Left_Should_Remove_Selection_Moving_Caret_To_End_Of_Previous_Selection(int selectionStart, int selectionEnd)
  1351. {
  1352. using (UnitTestApplication.Start(Services))
  1353. {
  1354. var tb = new TextBox
  1355. {
  1356. Template = CreateTemplate(),
  1357. Text = "ABCDEF"
  1358. };
  1359. tb.Measure(Size.Infinity);
  1360. tb.CaretIndex = selectionStart;
  1361. tb.SelectionStart = selectionStart;
  1362. tb.SelectionEnd = selectionEnd;
  1363. RaiseKeyEvent(tb, Key.Left, KeyModifiers.None);
  1364. Assert.Equal(selectionEnd, tb.SelectionStart);
  1365. Assert.Equal(selectionEnd, tb.SelectionEnd);
  1366. Assert.Equal(selectionEnd, tb.CaretIndex);
  1367. }
  1368. }
  1369. [Theory]
  1370. [InlineData(0)]
  1371. [InlineData(2)]
  1372. [InlineData(4)]
  1373. [InlineData(6)]
  1374. public void When_Select_All_From_Position_Left_Should_Remove_Selection_Moving_Caret_To_Start(int caretIndex)
  1375. {
  1376. using (UnitTestApplication.Start(Services))
  1377. {
  1378. var tb = new TextBox
  1379. {
  1380. Template = CreateTemplate(),
  1381. Text = "ABCDEF"
  1382. };
  1383. tb.Measure(Size.Infinity);
  1384. tb.CaretIndex = caretIndex;
  1385. RaiseKeyEvent(tb, Key.A, KeyModifiers.Control);
  1386. RaiseKeyEvent(tb, Key.Left, KeyModifiers.None);
  1387. Assert.Equal(0, tb.SelectionStart);
  1388. Assert.Equal(0, tb.SelectionEnd);
  1389. Assert.Equal(0, tb.CaretIndex);
  1390. }
  1391. }
  1392. [Theory]
  1393. [InlineData(0)]
  1394. [InlineData(2)]
  1395. [InlineData(4)]
  1396. [InlineData(6)]
  1397. public void When_Select_All_From_Position_Right_Should_Remove_Selection_Moving_Caret_To_End(int caretIndex)
  1398. {
  1399. using (UnitTestApplication.Start(Services))
  1400. {
  1401. var tb = new TextBox
  1402. {
  1403. Template = CreateTemplate(),
  1404. Text = "ABCDEF"
  1405. };
  1406. tb.Measure(Size.Infinity);
  1407. tb.CaretIndex = caretIndex;
  1408. RaiseKeyEvent(tb, Key.A, KeyModifiers.Control);
  1409. RaiseKeyEvent(tb, Key.Right, KeyModifiers.None);
  1410. Assert.Equal(tb.Text.Length, tb.SelectionStart);
  1411. Assert.Equal(tb.Text.Length, tb.SelectionEnd);
  1412. Assert.Equal(tb.Text.Length, tb.CaretIndex);
  1413. }
  1414. }
  1415. [Theory]
  1416. [InlineData(2,4)]
  1417. [InlineData(0,4)]
  1418. [InlineData(2,6)]
  1419. [InlineData(0,6)]
  1420. [InlineData(3,4)]
  1421. public void When_Selection_From_Left_To_Right_Pressing_Up_Should_Remove_Selection_Moving_Caret_To_Start_Of_Previous_Selection(int selectionStart, int selectionEnd)
  1422. {
  1423. using (UnitTestApplication.Start(Services))
  1424. {
  1425. var tb = new TextBox
  1426. {
  1427. Template = CreateTemplate(),
  1428. Text = "ABCDEF"
  1429. };
  1430. tb.Measure(Size.Infinity);
  1431. tb.CaretIndex = selectionStart;
  1432. tb.SelectionStart = selectionStart;
  1433. tb.SelectionEnd = selectionEnd;
  1434. RaiseKeyEvent(tb, Key.Up, KeyModifiers.None);
  1435. Assert.Equal(selectionStart, tb.SelectionStart);
  1436. Assert.Equal(selectionStart, tb.SelectionEnd);
  1437. Assert.Equal(selectionStart, tb.CaretIndex);
  1438. }
  1439. }
  1440. [Theory]
  1441. [InlineData(4,2)]
  1442. [InlineData(4,0)]
  1443. [InlineData(6,2)]
  1444. [InlineData(6,0)]
  1445. [InlineData(4,3)]
  1446. public void When_Selection_From_Right_To_Left_Pressing_Up_Should_Remove_Selection_Moving_Caret_To_End_Of_Previous_Selection(int selectionStart, int selectionEnd)
  1447. {
  1448. using (UnitTestApplication.Start(Services))
  1449. {
  1450. var tb = new TextBox
  1451. {
  1452. Template = CreateTemplate(),
  1453. Text = "ABCDEF"
  1454. };
  1455. tb.Measure(Size.Infinity);
  1456. tb.CaretIndex = selectionStart;
  1457. tb.SelectionStart = selectionStart;
  1458. tb.SelectionEnd = selectionEnd;
  1459. RaiseKeyEvent(tb, Key.Up, KeyModifiers.None);
  1460. Assert.Equal(selectionEnd, tb.SelectionStart);
  1461. Assert.Equal(selectionEnd, tb.SelectionEnd);
  1462. Assert.Equal(selectionEnd, tb.CaretIndex);
  1463. }
  1464. }
  1465. [Theory]
  1466. [InlineData(0)]
  1467. [InlineData(2)]
  1468. [InlineData(4)]
  1469. [InlineData(6)]
  1470. public void When_Select_All_From_Position_Up_Should_Remove_Selection_Moving_Caret_To_Start(int caretIndex)
  1471. {
  1472. using (UnitTestApplication.Start(Services))
  1473. {
  1474. var tb = new TextBox
  1475. {
  1476. Template = CreateTemplate(),
  1477. Text = "ABCDEF"
  1478. };
  1479. tb.Measure(Size.Infinity);
  1480. tb.CaretIndex = caretIndex;
  1481. RaiseKeyEvent(tb, Key.A, KeyModifiers.Control);
  1482. RaiseKeyEvent(tb, Key.Up, KeyModifiers.None);
  1483. Assert.Equal(0, tb.SelectionStart);
  1484. Assert.Equal(0, tb.SelectionEnd);
  1485. Assert.Equal(0, tb.CaretIndex);
  1486. }
  1487. }
  1488. [Theory]
  1489. [InlineData(2,4)]
  1490. [InlineData(0,4)]
  1491. [InlineData(2,6)]
  1492. [InlineData(0,6)]
  1493. [InlineData(3,4)]
  1494. public void When_Selection_From_Left_To_Right_Pressing_Down_Should_Remove_Selection_Moving_Caret_To_End_Of_Previous_Selection(int selectionStart, int selectionEnd)
  1495. {
  1496. using (UnitTestApplication.Start(Services))
  1497. {
  1498. var tb = new TextBox
  1499. {
  1500. Template = CreateTemplate(),
  1501. Text = "ABCDEF"
  1502. };
  1503. tb.Measure(Size.Infinity);
  1504. tb.CaretIndex = selectionStart;
  1505. tb.SelectionStart = selectionStart;
  1506. tb.SelectionEnd = selectionEnd;
  1507. RaiseKeyEvent(tb, Key.Down, KeyModifiers.None);
  1508. Assert.Equal(selectionEnd, tb.SelectionStart);
  1509. Assert.Equal(selectionEnd, tb.SelectionEnd);
  1510. Assert.Equal(selectionEnd, tb.CaretIndex);
  1511. }
  1512. }
  1513. [Theory]
  1514. [InlineData(4,2)]
  1515. [InlineData(4,0)]
  1516. [InlineData(6,2)]
  1517. [InlineData(6,0)]
  1518. [InlineData(4,3)]
  1519. public void When_Selection_From_Right_To_Left_Pressing_Down_Should_Remove_Selection_Moving_Caret_To_Start_Of_Previous_Selection(int selectionStart, int selectionEnd)
  1520. {
  1521. using (UnitTestApplication.Start(Services))
  1522. {
  1523. var tb = new TextBox
  1524. {
  1525. Template = CreateTemplate(),
  1526. Text = "ABCDEF"
  1527. };
  1528. tb.Measure(Size.Infinity);
  1529. tb.CaretIndex = selectionStart;
  1530. tb.SelectionStart = selectionStart;
  1531. tb.SelectionEnd = selectionEnd;
  1532. RaiseKeyEvent(tb, Key.Down, KeyModifiers.None);
  1533. Assert.Equal(selectionStart, tb.SelectionStart);
  1534. Assert.Equal(selectionStart, tb.SelectionEnd);
  1535. Assert.Equal(selectionStart, tb.CaretIndex);
  1536. }
  1537. }
  1538. [Theory]
  1539. [InlineData(0)]
  1540. [InlineData(2)]
  1541. [InlineData(4)]
  1542. [InlineData(6)]
  1543. public void When_Select_All_From_Position_Down_Should_Remove_Selection_Moving_Caret_To_End(int caretIndex)
  1544. {
  1545. using (UnitTestApplication.Start(Services))
  1546. {
  1547. var tb = new TextBox
  1548. {
  1549. Template = CreateTemplate(),
  1550. Text = "ABCDEF"
  1551. };
  1552. tb.Measure(Size.Infinity);
  1553. tb.CaretIndex = caretIndex;
  1554. RaiseKeyEvent(tb, Key.A, KeyModifiers.Control);
  1555. RaiseKeyEvent(tb, Key.Down, KeyModifiers.None);
  1556. Assert.Equal(tb.Text.Length, tb.SelectionStart);
  1557. Assert.Equal(tb.Text.Length, tb.SelectionEnd);
  1558. Assert.Equal(tb.Text.Length, tb.CaretIndex);
  1559. }
  1560. }
  1561. [Theory]
  1562. [InlineData(0)]
  1563. [InlineData(4)]
  1564. [InlineData(8)]
  1565. public void When_Selecting_Multiline_Selection_Should_Be_Extended_With_Up_Arrow_Key_Till_Start_Of_Text(int caretOffsetFromEnd)
  1566. {
  1567. using (UnitTestApplication.Start(Services))
  1568. {
  1569. var tb = new TextBox
  1570. {
  1571. Template = CreateTemplate(),
  1572. Text = """
  1573. AAAAAA
  1574. BBBB
  1575. CCCCCCCC
  1576. """,
  1577. AcceptsReturn = true
  1578. };
  1579. tb.ApplyTemplate();
  1580. tb.Measure(Size.Infinity);
  1581. tb.CaretIndex = tb.Text.Length - caretOffsetFromEnd;
  1582. RaiseKeyEvent(tb, Key.Up, KeyModifiers.Shift);
  1583. RaiseKeyEvent(tb, Key.Up, KeyModifiers.Shift);
  1584. RaiseKeyEvent(tb, Key.Up, KeyModifiers.Shift);
  1585. RaiseKeyEvent(tb, Key.Up, KeyModifiers.Shift);
  1586. Assert.Equal(0, tb.SelectionEnd);
  1587. }
  1588. }
  1589. [Theory]
  1590. [InlineData(0)]
  1591. [InlineData(3)]
  1592. [InlineData(6)]
  1593. public void When_Selecting_Multiline_Selection_Should_Be_Extended_With_Down_Arrow_Key_Till_End_Of_Text(int caretOffsetFromStart)
  1594. {
  1595. using (UnitTestApplication.Start(Services))
  1596. {
  1597. var tb = new TextBox
  1598. {
  1599. Template = CreateTemplate(),
  1600. Text = """
  1601. AAAAAA
  1602. BBBB
  1603. CCCCCCCC
  1604. """,
  1605. AcceptsReturn = true
  1606. };
  1607. tb.ApplyTemplate();
  1608. tb.Measure(Size.Infinity);
  1609. tb.CaretIndex = caretOffsetFromStart;
  1610. RaiseKeyEvent(tb, Key.Down, KeyModifiers.Shift);
  1611. RaiseKeyEvent(tb, Key.Down, KeyModifiers.Shift);
  1612. RaiseKeyEvent(tb, Key.Down, KeyModifiers.Shift);
  1613. RaiseKeyEvent(tb, Key.Down, KeyModifiers.Shift);
  1614. Assert.Equal(tb.Text.Length, tb.SelectionEnd);
  1615. }
  1616. }
  1617. [Fact]
  1618. public void TextBox_In_AdornerLayer_Will_Not_Cause_Collection_Modified_In_VisualLayerManager_Measure()
  1619. {
  1620. using (UnitTestApplication.Start(Services))
  1621. {
  1622. var button = new Button();
  1623. var root = new TestRoot()
  1624. {
  1625. Child = new VisualLayerManager()
  1626. {
  1627. Child = button
  1628. }
  1629. };
  1630. var adorner = new TextBox { Template = CreateTemplate(), Text = "a" };
  1631. var adornerLayer = AdornerLayer.GetAdornerLayer(button);
  1632. Assert.NotNull(adornerLayer);
  1633. adornerLayer.Children.Add(adorner);
  1634. AdornerLayer.SetAdornedElement(adorner, button);
  1635. root.Measure(Size.Infinity);
  1636. }
  1637. }
  1638. [Fact]
  1639. public void TextBox_In_AdornerLayer_Will_Not_Cause_Collection_Modified_In_VisualLayerManager_Arrange()
  1640. {
  1641. using (UnitTestApplication.Start(Services))
  1642. {
  1643. var button = new Button();
  1644. var visualLayerManager = new VisualLayerManager() { Child = button };
  1645. var root = new TestRoot()
  1646. {
  1647. Child = visualLayerManager
  1648. };
  1649. var adorner = new TextBox { Template = CreateTemplate(), Text = "a" };
  1650. var adornerLayer = AdornerLayer.GetAdornerLayer(button);
  1651. Assert.NotNull(adornerLayer);
  1652. root.Measure(new Size(10, 10));
  1653. adornerLayer.Children.Add(adorner);
  1654. AdornerLayer.SetAdornedElement(adorner, button);
  1655. root.Arrange(new Rect(0, 0, 10, 10));
  1656. }
  1657. }
  1658. [Theory]
  1659. [InlineData("A\nBB\nCCC\nDDDD", 0, 0)]
  1660. [InlineData("A\nBB\nCCC\nDDDD", 1, 2)]
  1661. [InlineData("A\nBB\nCCC\nDDDD", 2, 5)]
  1662. [InlineData("A\nBB\nCCC\nDDDD", 3, 9)]
  1663. [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 0, 0)]
  1664. [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 1, 5)]
  1665. [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 2, 11)]
  1666. [InlineData("واحد\nاثنين\nثلاثة\nأربعة", 3, 17)]
  1667. public void Should_Scroll_Caret_To_Line(string text, int targetLineIndex, int expectedCaretIndex)
  1668. {
  1669. using (UnitTestApplication.Start(Services))
  1670. {
  1671. var tb = new TextBox
  1672. {
  1673. Template = CreateTemplate(),
  1674. Text = text
  1675. };
  1676. tb.ApplyTemplate();
  1677. tb.ScrollToLine(targetLineIndex);
  1678. Assert.Equal(expectedCaretIndex, tb.CaretIndex);
  1679. }
  1680. }
  1681. [Fact]
  1682. public void Should_Throw_ArgumentOutOfRange()
  1683. {
  1684. using (UnitTestApplication.Start(Services))
  1685. {
  1686. var tb = new TextBox
  1687. {
  1688. Template = CreateTemplate(),
  1689. Text = string.Empty
  1690. };
  1691. tb.ApplyTemplate();
  1692. Assert.Throws<ArgumentOutOfRangeException>(() => tb.ScrollToLine(-1));
  1693. Assert.Throws<ArgumentOutOfRangeException>(() => tb.ScrollToLine(1));
  1694. }
  1695. }
  1696. [Fact]
  1697. public void InputMethodClient_SurroundingText_Returns_Empty_For_Empty_Line()
  1698. {
  1699. using var _ = UnitTestApplication.Start(Services);
  1700. var textBox = new TextBox
  1701. {
  1702. Template = CreateTemplate(),
  1703. Text = "",
  1704. CaretIndex = 0
  1705. };
  1706. textBox.ApplyTemplate();
  1707. var eventArgs = new TextInputMethodClientRequestedEventArgs
  1708. {
  1709. RoutedEvent = InputElement.TextInputMethodClientRequestedEvent
  1710. };
  1711. textBox.RaiseEvent(eventArgs);
  1712. var client = eventArgs.Client;
  1713. Assert.NotNull(client);
  1714. Assert.Equal(string.Empty, client.SurroundingText);
  1715. }
  1716. [Fact]
  1717. public void Backspace_Should_Delete_Last_Character_In_Line_And_Keep_Caret_On_Same_Line()
  1718. {
  1719. using var _ = UnitTestApplication.Start(Services);
  1720. var textBox = new TextBox
  1721. {
  1722. Template = CreateTemplate(),
  1723. Text = "a\nb",
  1724. CaretIndex = 3
  1725. };
  1726. textBox.ApplyTemplate();
  1727. var topLevel = new TestTopLevel(CreateMockTopLevelImpl().Object)
  1728. {
  1729. Template = CreateTopLevelTemplate(),
  1730. Content = textBox
  1731. };
  1732. topLevel.ApplyTemplate();
  1733. topLevel.LayoutManager.ExecuteInitialLayoutPass();
  1734. var textPresenter = textBox.FindDescendantOfType<TextPresenter>();
  1735. Assert.NotNull(textPresenter);
  1736. var oldCaretY = textPresenter.GetCursorRectangle().Top;
  1737. Assert.NotEqual(0, oldCaretY);
  1738. RaiseKeyEvent(textBox, Key.Back, KeyModifiers.None);
  1739. Assert.Equal("a\n", textBox.Text);
  1740. Assert.Equal(2, textBox.CaretIndex);
  1741. Assert.Equal(2, textPresenter.CaretIndex);
  1742. var caretY = textPresenter.GetCursorRectangle().Top;
  1743. Assert.Equal(oldCaretY, caretY);
  1744. }
  1745. [Fact]
  1746. public void Losing_Focus_Should_Not_Reset_Selection()
  1747. {
  1748. using (UnitTestApplication.Start(FocusServices))
  1749. {
  1750. var target1 = new TextBox
  1751. {
  1752. Template = CreateTemplate(),
  1753. Text = "1234",
  1754. ClearSelectionOnLostFocus = false
  1755. };
  1756. target1.ApplyTemplate();
  1757. var target2 = new TextBox
  1758. {
  1759. Template = CreateTemplate(),
  1760. };
  1761. target2.ApplyTemplate();
  1762. var sp = new StackPanel();
  1763. sp.Children.Add(target1);
  1764. sp.Children.Add(target2);
  1765. var root = new TestRoot() { Child = sp };
  1766. target1.SelectionStart = 0;
  1767. target1.SelectionEnd = 4;
  1768. target1.Focus();
  1769. Assert.True(target1.IsFocused);
  1770. Assert.Equal("1234", target1.SelectedText);
  1771. target2.Focus();
  1772. Assert.Equal("1234", target1.SelectedText);
  1773. }
  1774. }
  1775. private static TestServices FocusServices => TestServices.MockThreadingInterface.With(
  1776. keyboardDevice: () => new KeyboardDevice(),
  1777. keyboardNavigation: () => new KeyboardNavigationHandler(),
  1778. inputManager: new InputManager(),
  1779. standardCursorFactory: Mock.Of<ICursorFactory>(),
  1780. textShaperImpl: new HeadlessTextShaperStub(),
  1781. fontManagerImpl: new HeadlessFontManagerStub());
  1782. private static TestServices Services => TestServices.MockThreadingInterface.With(
  1783. standardCursorFactory: Mock.Of<ICursorFactory>(),
  1784. renderInterface: new HeadlessPlatformRenderInterface(),
  1785. textShaperImpl: new HeadlessTextShaperStub(),
  1786. fontManagerImpl: new HeadlessFontManagerStub());
  1787. internal static IControlTemplate CreateTemplate()
  1788. {
  1789. return new FuncControlTemplate<TextBox>((control, scope) =>
  1790. new ScrollViewer
  1791. {
  1792. Name = "PART_ScrollViewer",
  1793. Template = new FuncControlTemplate<ScrollViewer>(ScrollViewerTests.CreateTemplate),
  1794. Content = new TextPresenter
  1795. {
  1796. Name = "PART_TextPresenter",
  1797. [!!TextPresenter.TextProperty] = new Binding
  1798. {
  1799. Path = nameof(TextPresenter.Text),
  1800. Mode = BindingMode.TwoWay,
  1801. Priority = BindingPriority.Template,
  1802. RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
  1803. },
  1804. [!!TextPresenter.CaretIndexProperty] = new Binding
  1805. {
  1806. Path = nameof(TextPresenter.CaretIndex),
  1807. Mode = BindingMode.TwoWay,
  1808. Priority = BindingPriority.Template,
  1809. RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
  1810. }
  1811. }.RegisterInNameScope(scope)
  1812. }.RegisterInNameScope(scope));
  1813. }
  1814. private static void RaiseKeyEvent(TextBox textBox, Key key, KeyModifiers inputModifiers)
  1815. {
  1816. textBox.RaiseEvent(new KeyEventArgs
  1817. {
  1818. RoutedEvent = InputElement.KeyDownEvent,
  1819. KeyModifiers = inputModifiers,
  1820. Key = key
  1821. });
  1822. }
  1823. private static void RaiseTextEvent(TextBox textBox, string text)
  1824. {
  1825. textBox.RaiseEvent(new TextInputEventArgs
  1826. {
  1827. RoutedEvent = InputElement.TextInputEvent,
  1828. Text = text
  1829. });
  1830. }
  1831. private class Class1 : NotifyingBase
  1832. {
  1833. private int _foo;
  1834. private string? _bar;
  1835. public int Foo
  1836. {
  1837. get { return _foo; }
  1838. set { _foo = value; RaisePropertyChanged(); }
  1839. }
  1840. public string? Bar
  1841. {
  1842. get { return _bar; }
  1843. set { _bar = value; RaisePropertyChanged(); }
  1844. }
  1845. }
  1846. private class TestTopLevel : TopLevel
  1847. {
  1848. private readonly ILayoutManager _layoutManager;
  1849. public TestTopLevel(ITopLevelImpl impl, ILayoutManager? layoutManager = null)
  1850. : base(impl)
  1851. {
  1852. _layoutManager = layoutManager ?? new LayoutManager(this);
  1853. }
  1854. private protected override ILayoutManager CreateLayoutManager() => _layoutManager;
  1855. }
  1856. private static Mock<ITopLevelImpl> CreateMockTopLevelImpl()
  1857. {
  1858. var clipboard = new Mock<ITopLevelImpl>();
  1859. clipboard.Setup(x => x.Compositor).Returns(RendererMocks.CreateDummyCompositor());
  1860. clipboard.Setup(r => r.TryGetFeature(typeof(IClipboard)))
  1861. .Returns(new Clipboard(new HeadlessClipboardImplStub()));
  1862. clipboard.SetupGet(x => x.RenderScaling).Returns(1);
  1863. return clipboard;
  1864. }
  1865. private static FuncControlTemplate<TestTopLevel> CreateTopLevelTemplate()
  1866. {
  1867. return new FuncControlTemplate<TestTopLevel>((x, scope) =>
  1868. new ContentPresenter
  1869. {
  1870. Name = "PART_ContentPresenter",
  1871. [!ContentPresenter.ContentProperty] = x[!ContentControl.ContentProperty],
  1872. }.RegisterInNameScope(scope));
  1873. }
  1874. private class TestContextMenu : ContextMenu
  1875. {
  1876. public TestContextMenu()
  1877. {
  1878. IsOpen = true;
  1879. }
  1880. }
  1881. }
  1882. }