3 // Moonlight List (moonlight-list@lists.ximian.com)
5 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
7 // Permission is hereby granted, free of charge, to any person obtaining
8 // a copy of this software and associated documentation files (the
9 // "Software"), to deal in the Software without restriction, including
10 // without limitation the rights to use, copy, modify, merge, publish,
11 // distribute, sublicense, and/or sell copies of the Software, and to
12 // permit persons to whom the Software is furnished to do so, subject to
13 // the following conditions:
15 // The above copyright notice and this permission notice shall be
16 // included in all copies or substantial portions of the Software.
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System
.Windows
.Controls
;
31 using System
.Windows
.Documents
;
32 using System
.Windows
.Ink
;
33 using System
.Windows
.Input
;
34 using System
.Windows
.Media
;
35 using System
.Windows
.Media
.Animation
;
36 using System
.Windows
.Shapes
;
37 using System
.Collections
.Generic
;
38 using System
.Windows
.Markup
;
39 using Microsoft
.VisualStudio
.TestTools
.UnitTesting
;
40 using Microsoft
.Silverlight
.Testing
;
41 using Mono
.Moonlight
.UnitTesting
;
43 namespace MoonTest
.System
.Windows
46 public class LoadedTest
: SilverlightTest
48 public class MyComboBox
: ComboBox
50 public bool AppliedTemplate { get; private set; }
52 public override void OnApplyTemplate ()
54 AppliedTemplate
= true;
55 base.OnApplyTemplate ();
59 void AddThenRemove_test (bool match_tick_numbers
)
64 Canvas c
= new Canvas ();
65 MyComboBox b
= new MyComboBox ();
66 MyComboBox second
= new MyComboBox ();
68 b
.Loaded
+= delegate { b_count++; }
;
69 c
.Loaded
+= delegate { c_count++; }
;
73 TestPanel
.Children
.Add (c
);
74 EnqueueConditional (() => b_count
== 1 && c_count
== 1, "#1");
76 // If an item with delayed loaded emission is added to the tree, the entire tree
77 // will be walked to find Loaded handlers which have not been emitted and will emit
78 // those. The handlers will be invoked the tick *after* the template is applied.
80 b
.Loaded
+= delegate { b_count += 10; }
;
81 c
.Loaded
+= delegate { c_count += 10; }
;
83 c
.Children
.Add (second
);
84 Assert
.IsFalse (second
.AppliedTemplate
, "#AppliedTemplate 1");
87 Assert
.IsTrue (second
.AppliedTemplate
, "#AppliedTemplate 2");
89 if (match_tick_numbers
) {
90 // in moonlight the c.Children.Add posts the
91 // loaded event emission hook for async use, but the
92 // render callback is invoked right after the Enqueue
93 // which happens from a DispatcherTimer (an
96 // therefore the properties are updated after the
97 // previous Enqueue, but before this one.
99 Assert
.AreEqual (1, b_count
, "#2");
100 Assert
.AreEqual (1, c_count
, "#3");
103 // Adding an item with immediate loaded emission doesn't invoke new
104 // Loaded handlers on its parent UIElements
106 Assert
.AreEqual (11, b_count
, "#4");
107 Assert
.AreEqual (11, c_count
, "#5");
109 b
.Loaded
+= delegate { b_count += 100; }
;
110 c
.Loaded
+= delegate { c_count += 100; }
;
111 c
.Children
.Add (new Canvas ());
114 Assert
.AreEqual (11, b_count
, "#6");
115 Assert
.AreEqual (11, c_count
, "#7");
117 EnqueueTestComplete ();
122 public void AddThenRemove ()
124 AddThenRemove_test (false);
129 [MoonlightBug ("see comment in AddThenRemove_test")]
130 public void AddThenRemove_strictOrdering ()
132 AddThenRemove_test (true);
137 public void AddTwice ()
139 AddTwice_test (false);
144 [MoonlightBug ("see comment in AddThenRemove_test")]
145 public void AddTwice_strictOrdering ()
147 AddTwice_test (true);
150 public void AddTwice_test (bool match_tick_numbers
)
152 // If we add a handler both before and after we add a templated item
153 // to the tree, check to ensure that both handlers get called immediately
154 // if the element is removed and added again.
157 ComboBox box
= new ComboBox ();
158 box
.Loaded
+= delegate { before++; }
;
159 TestPanel
.Children
.Add (box
);
160 box
.Loaded
+= delegate { after++; }
;
162 // The first handler should have emitted now.
163 Assert
.AreEqual (1, before
, "#1");
165 if (match_tick_numbers
) {
166 // The template has been applied this tick, so the
167 // second handler will invoke during the next tick
168 Assert
.AreEqual (0, after
, "#2");
172 Assert
.AreEqual (1, before
, "#3");
173 Assert
.AreEqual (1, after
, "#4");
175 // Both handlers should emit again now.
176 TestPanel
.Children
.Clear ();
177 TestPanel
.Children
.Add (box
);
180 Assert
.AreEqual (2, before
, "#5");
181 Assert
.AreEqual (2, after
, "#6");
183 EnqueueTestComplete ();
188 public void AsyncLoaded ()
190 // Attach the handler before adding the control to the tree.
192 Border b
= new Border ();
194 b
.Loaded
+= delegate { loaded = true; }
;
195 TestPanel
.Children
.Add (b
);
197 // Loaded is not raised synchronously
198 Assert
.IsFalse (loaded
, "Not syncronous");
200 EnqueueConditional (() => loaded
, "Loaded should be raised");
201 EnqueueTestComplete ();
206 [ExpectedException (typeof (Exception
))]
207 public void AsyncLoaded2 ()
209 // Attach the handler after the control is added to the tree
211 Border b
= new Border ();
213 TestPanel
.Children
.Add (b
);
214 b
.Loaded
+= delegate { loaded = true; }
;
216 // The handler is never invoked - this is a standard async event.
217 Assert
.IsFalse (loaded
, "Not syncronous");
219 EnqueueConditional (() => loaded
, TimeSpan
.FromSeconds (1), "This should time out");
220 EnqueueTestComplete ();
225 public void ChildForcesParentToEmitLoad ()
227 ChildForcesParentToEmitLoad_test (false);
232 [MoonlightBug ("see comment in AddThenRemove_test")]
233 public void ChildForcesParentToEmitLoad_strictOrdering ()
235 ChildForcesParentToEmitLoad_test (true);
238 public void ChildForcesParentToEmitLoad_test (bool match_tick_numbers
)
241 TestPanel
.Loaded
+= delegate { loaded = true; }
;
242 TestPanel
.Children
.Add (new ComboBox ());
244 if (match_tick_numbers
)
245 Assert
.IsFalse (loaded
, "#1");
248 // When the ComboBoxs Template expands, it forces the
249 // canvas to call any unemitted Loaded handlers.
250 Assert
.IsTrue (loaded
, "#2");
252 EnqueueTestComplete ();
257 public void ControlLoaded ()
260 ItemsControl c
= new ItemsControl ();
261 c
.Loaded
+= delegate { loaded = true; }
;
262 TestPanel
.Children
.Add (c
);
263 EnqueueConditional (() => loaded
);
264 EnqueueTestComplete ();
269 [ExpectedException (typeof (Exception
))]
270 public void ControlLoaded2 ()
273 ItemsControl c
= new ItemsControl ();
274 TestPanel
.Children
.Add (c
);
275 c
.Loaded
+= delegate { loaded = true; }
;
276 EnqueueConditional (() => loaded
);
277 EnqueueTestComplete ();
282 public void DefaultStyleApply ()
284 ComboBox box
= new ComboBox ();
285 Assert
.IsNull (box
.Style
, "#1");
286 Assert
.IsNull (box
.Template
, "#2");
287 TestPanel
.Children
.Add (box
);
288 Assert
.IsNull (box
.Style
, "#3");
289 Assert
.IsNotNull (box
.Template
, "#4");
290 Assert
.IsUnset (box
, Control
.TemplateProperty
, "#5");
293 Assert
.IsNull (box
.Style
, "#5");
295 EnqueueTestComplete ();
300 public void EmitBeforeAndAfter ()
302 EmitBeforeAndAfter_test (false);
307 [MoonlightBug ("see comment in AddThenRemove_test")]
308 public void EmitBeforeAndAfter_strictOrdering ()
310 EmitBeforeAndAfter_test (true);
313 public void EmitBeforeAndAfter_test (bool match_tick_numbers
)
315 // Adding a templated control to the visual tree results in a second Loaded
316 // being emitted *after* the template expands for that control.
317 bool before_b
= false;
318 bool before_c
= false;
319 bool after_b
= false;
320 bool after_c
= false;
322 Canvas c
= new Canvas ();
323 ComboBox b
= new ComboBox ();
326 c
.Loaded
+= delegate { before_c = true; }
;
327 b
.Loaded
+= delegate { before_b = true; }
;
328 TestPanel
.Children
.Add (c
);
329 c
.Loaded
+= delegate { after_c = true; }
;
330 b
.Loaded
+= delegate { after_b = true; }
;
333 Assert
.IsTrue (before_b
, "#1");
334 Assert
.IsTrue (before_c
, "#2");
335 if (match_tick_numbers
) {
336 Assert
.IsFalse (after_b
, "#3");
337 Assert
.IsFalse (after_c
, "#4");
341 Assert
.IsTrue (after_b
, "#3");
342 Assert
.IsTrue (after_c
, "#4");
344 EnqueueTestComplete ();
349 public void EmitBeforeAndAfter2 ()
351 // If we call ApplyTemplate (), the second set of Loaded
352 // events is emitted immediately.
353 bool before_b
= false;
354 bool before_c
= false;
355 bool after_b
= false;
356 bool after_c
= false;
358 Canvas c
= new Canvas ();
359 ComboBox b
= new ComboBox ();
362 c
.Loaded
+= delegate { before_c = true; }
;
363 b
.Loaded
+= delegate { before_b = true; }
;
364 TestPanel
.Children
.Add (c
);
365 c
.Loaded
+= delegate { after_c = true; }
;
366 b
.Loaded
+= delegate { after_b = true; }
;
368 // Calling 'ApplyTemplate' emits the Loaded
369 // events for the template, so all handlers will
370 // be raised during the next tick.
374 Assert
.IsTrue (before_b
, "#1");
375 Assert
.IsTrue (before_c
, "#2");
376 Assert
.IsTrue (after_b
, "#3");
377 Assert
.IsTrue (after_c
, "#4");
379 EnqueueTestComplete ();
384 [MoonlightBug ("we don't emit Loaded events in insertion order")]
385 public void ForceEventEmission ()
387 // If we add a control which does *not* have a loaded handler
388 // attached, then we don't force emission of other Loaded handlers in
389 // the order in which they're added.
390 ForceEventEmissionImpl (false);
395 [MoonlightBug ("we don't emit Loaded events in insertion order")]
396 public void ForceEventEmission2 ()
398 // If we add a control which *does* have a loaded handler
399 // attached, then we force emission of other Loaded handlers in
400 // the order in which they're added.
401 ForceEventEmissionImpl (true);
404 public void ForceEventEmissionImpl (bool attachLoadedHandler
)
408 Canvas box
= new Canvas ();// ComboBox box = new ComboBox { Style = null, Template = null };
409 Canvas container
= new Canvas ();
411 Canvas main
= new Canvas ();
412 Canvas child
= new Canvas ();
413 Canvas baby
= new Canvas ();
415 main
.Children
.Add (child
);
416 child
.Children
.Add (baby
);
418 EnqueueWaitLoaded (container
, "#1");
419 EnqueueWaitLoaded (main
, "#2");
421 TestPanel
.Children
.Add (container
);
422 TestPanel
.Children
.Add (main
);
425 // NOTE: The normal order of event emission is bottom->top but in
426 // this case the handlers are emitted in the order they're added
427 baby
.Loaded
+= delegate { loaded += "baby"; }
;
428 main
.Loaded
+= delegate { loaded += "main"; }
;
429 child
.Loaded
+= delegate { loaded += "child"; }
;
431 if (attachLoadedHandler
)
432 box
.Loaded
+= delegate { }
;
434 container
.Children
.Add (box
);
436 child
.Loaded
+= delegate { loaded += "baby2"; }
;
437 main
.Loaded
+= delegate { loaded += "main2"; }
;
438 baby
.Loaded
+= delegate { loaded += "child2"; }
;
441 Assert
.AreEqual (attachLoadedHandler
? "babymainchild" : "", loaded
, "#3");
444 Assert
.AreEqual (attachLoadedHandler
? "babymainchild" : "", loaded
, "#4");
445 //And force the second set
447 Canvas c
= new Canvas ();
448 c
.Loaded
+= delegate { }
;
449 TestPanel
.Children
.Add (c
);
452 // If the first element had a Loaded handler attached, then we should only get the second set of handlers
453 // Otherwise we get both sets.
454 Assert
.AreEqual (attachLoadedHandler
? "baby2main2child2" : "babymainchildbaby2main2child2", loaded
, "#5");
456 EnqueueTestComplete ();
461 public void ForceEventEmission3 ()
463 // Add a canvas to the tree and wait for it to load.
464 // Add a second Loaded handler which won't be invoked
465 // initially and then poke it til it invokes.
468 Canvas c
= new Canvas ();
469 EnqueueWaitLoaded (c
, "#1");
470 TestPanel
.Children
.Add (c
);
472 c
.Loaded
+= delegate { count ++;}
;
474 // Second handler hasn't invoked
475 Enqueue (() => Assert
.AreEqual (0, count
, "#2"));
478 // This should not cause the second handler to invoke
479 Assert
.AreEqual (0, count
, "#3");
481 TestPanel
.Children
.Add (c
);
484 // This will cause it to be invoked
485 Assert
.AreEqual (0, count
, "#4");
487 c
.Loaded
+= delegate { }
;
488 TestPanel
.Children
.Add (c
);
490 Enqueue (() => Assert
.AreEqual (1, count
, "#5"));
491 EnqueueTestComplete ();
496 public void LoadedOrdering ()
498 List
<string> ordering
= new List
<string> ();
499 RoutedEventHandler loadedHandler
= (o
, e
) => ordering
.Add (((FrameworkElement
) o
).Name
);
501 Canvas a
= new Canvas { Name = "a" }
;
502 Canvas a1
= new Canvas { Name = "a1" }
;
505 Canvas b
= new Canvas { Name = "b" }
;
506 Canvas b1
= new Canvas { Name = "b1" }
;
509 a
.Loaded
+= loadedHandler
;
510 a1
.Loaded
+= loadedHandler
;
511 b
.Loaded
+= loadedHandler
;
512 b1
.Loaded
+= loadedHandler
;
514 TestPanel
.Children
.Add (a
);
518 Assert
.AreEqual (4, ordering
.Count
, "#1");
519 Assert
.AreEqual ("a1", ordering
[0], "#2");
520 Assert
.AreEqual ("a", ordering
[1], "#3");
521 Assert
.AreEqual ("b1", ordering
[2], "#4");
522 Assert
.AreEqual ("b", ordering
[3], "#5");
525 EnqueueTestComplete ();
530 [ExpectedException (typeof (Exception
))]
531 public void LoadedA1 ()
533 // Adding the handler after adding the item to the panel will
534 // prevent the handler being invoked
535 var box
= new ItemsControl ();
536 TestPanel
.Children
.Add (box
);
537 EnqueueWaitLoaded (box
, "#1");
538 EnqueueTestComplete ();
543 public void LoadedA2 ()
545 // If the applied default style contains no 'template', the loaded
546 // handler is invoked inside ElementAdded as a regular async event
547 var box
= new ItemsControl ();
548 EnqueueWaitLoaded (box
, "#1");
549 TestPanel
.Children
.Add (box
);
550 Enqueue (() => Assert
.IsNull (box
.Template
, "#2"));
551 EnqueueTestComplete ();
556 public void LoadedA3 ()
558 // A user set Template should result in standard behaviour
559 ItemsControl c
= (ItemsControl
) XamlReader
.Load (@"
561 xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
562 xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
563 <ItemsControl.Template>
567 </ItemsControl.Template>
571 c
.Loaded
+= (o
,e
) => { loaded = true; }
;
572 TestPanel
.Children
.Add (c
);
573 Assert
.IsFalse (loaded
, "#1");
574 EnqueueWaitLoaded (c
, "#2");
575 EnqueueTestComplete ();
581 public void LoadedB1 ()
583 // The ComboBox default style contains a Template, therefore we delay
584 // the WalkTreeForLoaded call until after the default style is applied
585 // and then do our tree walk. This allows us to add a handler *after*
586 // the element is added to the tree and still have it invoked
587 var box
= new ComboBox ();
588 TestPanel
.Children
.Add (box
);
589 EnqueueWaitLoaded (box
, "#1");
590 Enqueue (() => Assert
.IsNotNull (box
.Template
, "#2"));
591 Enqueue (() => Assert
.IsUnset (box
, Control
.TemplateProperty
, "#3"));
592 EnqueueTestComplete ();
597 [ExpectedException (typeof (Exception
))]
598 public void LoadedB2 ()
600 // If we explicitly put in 'null' as the template, it overrides the one
601 // provided in the default style, so we treat this as an untemplated
602 // item and do the regular treewalk.
603 var box
= new ComboBox ();
605 TestPanel
.Children
.Add (box
);
606 EnqueueWaitLoaded (box
, "#1");
607 Enqueue (() => Assert
.IsNotNull (box
.Template
, "#2"));
608 EnqueueTestComplete ();
613 [ExpectedException (typeof (Exception
))]
615 public void LoadedB3 ()
617 // A user set Template should result in standard behaviour
618 ComboBox c
= (ComboBox
) XamlReader
.Load (@"
620 xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
621 xmlns:x=""http://schemas.microsoft.com/winfx/2006/xaml"">
629 TestPanel
.Children
.Add (c
);
630 EnqueueWaitLoaded (c
, "#1");
631 EnqueueTestComplete ();
636 public void LoadedC1 ()
638 List
<string> ordering
= new List
<string> ();
639 Canvas container
= new Canvas ();
641 Canvas c
= new Canvas ();
642 ComboBox b
= new ComboBox ();
643 b
.Loaded
+= delegate { ordering.Add ("box"); }
;
644 c
.Loaded
+= delegate { ordering.Add ("canvas"); }
;
646 EnqueueWaitLoaded (container
, "#1");
647 TestPanel
.Children
.Add (container
);
650 TestPanel
.Children
.Add (b
);
651 container
.Children
.Add (c
);
654 EnqueueWaitLoaded (b
, "#2");
655 EnqueueWaitLoaded (c
, "#3");
658 Assert
.AreEqual ("box", ordering
[0], "#4");
659 Assert
.AreEqual ("canvas", ordering
[1], "#5");
661 EnqueueTestComplete ();
666 public void LoadedC2 ()
668 List
<string> ordering
= new List
<string> ();
670 Canvas container
= new Canvas ();
671 Canvas last
= new Canvas ();
672 Canvas first
= new Canvas ();
673 ComboBox box
= new ComboBox ();
676 container
.Loaded
+= (o
, e
) => ordering
.Add ("container");
677 last
.Loaded
+= (o
, e
) => ordering
.Add ("last");
678 first
.Loaded
+= (o
, e
) => ordering
.Add ("first");
679 box
.Loaded
+= (o
, e
) => ordering
.Add ("box");
680 container
.Children
.Add (box
);
682 TestPanel
.Children
.Add (first
);
683 TestPanel
.Children
.Add (container
);
684 TestPanel
.Children
.Add (last
);
686 EnqueueWaitLoaded (container
, "#1");
687 EnqueueWaitLoaded (box
, "#2");
689 Assert
.AreEqual ("first", ordering
[0], "#3");
690 Assert
.AreEqual ("box", ordering
[1], "#4");
691 Assert
.AreEqual ("container", ordering
[2], "#5");
692 Assert
.AreEqual ("last", ordering
[3], "#6");
694 EnqueueTestComplete ();
699 public void LoadedC3 ()
701 Canvas c
= new Canvas ();
702 ComboBox b
= new ComboBox ();
705 TestPanel
.Children
.Add (c
);
706 EnqueueWaitLoaded (c
, "#1");
707 EnqueueWaitLoaded (b
, "#2");
708 EnqueueTestComplete ();
713 public void LoadedD ()
715 List
<string> ordering
= new List
<string> ();
716 Canvas c
= new Canvas ();
717 ComboBox b
= new ComboBox ();
719 c
.Loaded
+= delegate { ordering.Add ("canvas"); }
;
720 b
.Loaded
+= delegate { ordering.Add ("box"); }
;
722 EnqueueWaitLoaded (c
, "#1");
723 EnqueueWaitLoaded (b
, "#2");
725 TestPanel
.Children
.Add (b
);
726 TestPanel
.Children
.Add (c
);
729 Assert
.AreEqual ("box", ordering
[0], "#4");
730 Assert
.AreEqual ("canvas", ordering
[1], "#3");
732 EnqueueTestComplete ();
737 public void RemoveAfterAdded ()
739 // See what happens if we add/remove the same element
740 // multiple times in a row.
742 ComboBox box
= new ComboBox ();
744 box
.Loaded
+= delegate { loaded++; }
;
745 TestPanel
.Children
.Add (box
);
746 TestPanel
.Children
.Clear ();
747 TestPanel
.Children
.Add (box
);
748 TestPanel
.Children
.Clear ();
749 TestPanel
.Children
.Add (box
);
752 Assert
.AreEqual (3, loaded
, "#1");
754 EnqueueTestComplete ();
759 public void RemoveAfterTemplateLoaded ()
761 RemoveAfterTemplateLoaded_test (false);
766 [MoonlightBug ("see comment in AddThenRemove_test")]
767 public void RemoveAfterTemplateLoaded_strictOrdering ()
769 RemoveAfterTemplateLoaded_test (true);
772 public void RemoveAfterTemplateLoaded_test (bool match_tick_numbers
)
776 ComboBox box
= new ComboBox ();
778 box
.Loaded
+= delegate { before++; }
;
779 TestPanel
.Children
.Add (box
);
780 box
.Loaded
+= delegate { after++; }
;
783 Assert
.AreEqual (1, before
, "#1");
784 if (match_tick_numbers
) {
785 Assert
.AreEqual (0, after
, "#2");
787 box
.ApplyTemplate ();
788 TestPanel
.Children
.Clear ();
791 Assert
.AreEqual (1, before
, "#3");
792 Assert
.AreEqual (1, after
, "#4");
795 // Make sure that the values really aren't changing
796 Assert
.AreEqual (1, before
, "#5");
797 Assert
.AreEqual (1, after
, "#6");
800 EnqueueTestComplete ();
805 public void RemoveBeforeTemplateLoaded ()
809 ComboBox box
= new ComboBox ();
811 box
.Loaded
+= delegate { before++; }
;
812 TestPanel
.Children
.Add (box
);
813 box
.Loaded
+= delegate { after++; }
;
814 TestPanel
.Children
.Clear ();
817 Assert
.AreEqual (1, before
, "#1");
818 Assert
.AreEqual (0, after
, "#2");
821 // Make sure that the second handler definitely hasn't being called
822 Assert
.AreEqual (1, before
, "#3");
823 Assert
.AreEqual (0, after
, "#4");
825 // Apply the template and see if this causes Loaded emission
826 Assert
.IsTrue (box
.ApplyTemplate (), "#5");
829 Assert
.AreEqual (1, before
, "#6");
830 Assert
.AreEqual (0, after
, "#7");
833 EnqueueTestComplete ();