@@ -227,4 +227,140 @@ protected override bool OnTextChanging (string newText)
227227 return BaseReturnedCancel ;
228228 }
229229 }
230+
231+ // --- CR feedback regression tests ---
232+
233+ /// <summary>
234+ /// Verifies that when TextField's TextChanging subscriber modifies text, and then a
235+ /// subsequent base TextChanging event cancels, the stale modified text does not leak
236+ /// into the next successful text change.
237+ /// </summary>
238+ [ Fact ]
239+ public void TextField_PendingText_ClearedOnBaseCancel ( )
240+ {
241+ // Copilot
242+ TextField tf = new ( ) { Width = 20 , Height = 1 } ;
243+ tf . Text = "initial" ;
244+
245+ // First: a subscriber modifies text via ResultEventArgs
246+ tf . TextChanging += ( _ , args ) =>
247+ {
248+ if ( args . Result == "modified" )
249+ {
250+ args . Result = "subscriber_changed" ;
251+ }
252+ } ;
253+
254+ tf . Text = "modified" ;
255+ Assert . Equal ( "subscriber_changed" , tf . Text ) ;
256+
257+ // Now subscribe to base View.TextChanging to cancel the NEXT change
258+ var cancelOnce = true ;
259+
260+ ( ( View ) tf ) . TextChanging += ( _ , e ) =>
261+ {
262+ if ( cancelOnce )
263+ {
264+ e . Cancel = true ;
265+ cancelOnce = false ;
266+ }
267+ } ;
268+
269+ // This should be cancelled by the base event
270+ tf . Text = "blocked" ;
271+ Assert . Equal ( "subscriber_changed" , tf . Text ) ;
272+
273+ // Next change should succeed with fresh text, NOT stale _pendingText
274+ tf . Text = "final" ;
275+ Assert . Equal ( "final" , tf . Text ) ;
276+ }
277+
278+ /// <summary>
279+ /// Verifies that TextValidateField does not raise View.TextChanged when
280+ /// ValueChanging is cancelled (CWP semantics: cancel suppresses TextChanged).
281+ /// </summary>
282+ [ Fact ]
283+ public void TextValidateField_ValueChangingCancel_SuppressesTextChanged ( )
284+ {
285+ // Copilot
286+ TextValidateField field = new ( ) { Width = 20 , Height = 1 } ;
287+
288+ // Set a provider that accepts any text
289+ field . Provider = new TextRegexProvider ( ".*" ) ;
290+ field . Text = "initial" ;
291+
292+ // Cancel ValueChanging
293+ field . ValueChanging += ( _ , args ) => args . Handled = true ;
294+
295+ bool textChangedRaised = false ;
296+ ( ( View ) field ) . TextChanged += ( _ , _ ) => textChangedRaised = true ;
297+
298+ field . Text = "blocked" ;
299+
300+ Assert . False ( textChangedRaised , "TextChanged should not fire when ValueChanging cancels" ) ;
301+ Assert . Equal ( "initial" , field . Text ) ;
302+ }
303+
304+ /// <summary>
305+ /// Verifies that DatePicker rejects invalid (unparseable) text: Text should not
306+ /// persist an invalid string that cannot round-trip through DateTime.
307+ /// </summary>
308+ [ Fact ]
309+ public void DatePicker_InvalidText_DoesNotPersist ( )
310+ {
311+ // Copilot
312+ DatePicker dp = new ( ) { Width = 20 , Height = 1 } ;
313+ DateTime originalValue = dp . Value ;
314+ string originalText = dp . Text ;
315+
316+ // Set invalid date text
317+ dp . Text = "not-a-date" ;
318+
319+ // Value should remain unchanged
320+ Assert . Equal ( originalValue , dp . Value ) ;
321+
322+ // Text should NOT hold the invalid string — it should revert or be rejected
323+ Assert . NotEqual ( "not-a-date" , dp . Text ) ;
324+ }
325+
326+ /// <summary>
327+ /// Verifies that ColorPicker rejects invalid (unparseable) text: Text should not
328+ /// persist an invalid string that cannot round-trip through Color.
329+ /// </summary>
330+ [ Fact ]
331+ public void ColorPicker_InvalidText_DoesNotPersist ( )
332+ {
333+ // Copilot
334+ ColorPicker cp = new ( ) { Width = 20 , Height = 3 } ;
335+ cp . SelectedColor = new Color ( 255 , 0 , 0 ) ;
336+ string originalText = cp . Text ;
337+
338+ // Set invalid color text
339+ cp . Text = "not-a-color" ;
340+
341+ // SelectedColor should remain unchanged
342+ Assert . Equal ( new Color ( 255 , 0 , 0 ) , cp . SelectedColor ) ;
343+
344+ // Text should NOT hold the invalid string — it should revert or be rejected
345+ Assert . NotEqual ( "not-a-color" , cp . Text ) ;
346+ }
347+
348+ /// <summary>
349+ /// Verifies that setting View.Text on a word-wrapped TextView via a View reference
350+ /// does not corrupt or redundantly re-process the model.
351+ /// </summary>
352+ [ Fact ]
353+ public void TextView_WordWrap_PolymorphicSet_DoesNotCorruptModel ( )
354+ {
355+ // Copilot
356+ TextView tv = new ( ) { Width = 10 , Height = 5 , WordWrap = true } ;
357+ tv . Text = "Hello World this wraps" ;
358+
359+ // Set via polymorphic View reference
360+ View viewRef = tv ;
361+ viewRef . Text = "Short" ;
362+
363+ Assert . Equal ( "Short" , tv . Text ) ;
364+ Assert . Equal ( "Short" , viewRef . Text ) ;
365+ }
230366}
0 commit comments