WPF Fundamentals

4,122 views
3,982 views

Published on

WPF Fundamentals

Published in: Design, Technology, Business
0 Comments
6 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
4,122
On SlideShare
0
From Embeds
0
Number of Embeds
208
Actions
Shares
0
Downloads
2
Comments
0
Likes
6
Embeds 0
No embeds

No notes for slide
  • 06/10/09 15:24 © 2007 Microsoft Corporation. All rights reserved. Microsoft, Windows, Windows Vista and other product names are or may be registered trademarks and/or trademarks in the U.S. and/or other countries. The information herein is for informational purposes only and represents the current view of Microsoft Corporation as of the date of this presentation. Because Microsoft must respond to changing market conditions, it should not be interpreted to be a commitment on the part of Microsoft, and Microsoft cannot guarantee the accuracy of any information provided after the date of this presentation. MICROSOFT MAKES NO WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, AS TO THE INFORMATION IN THIS PRESENTATION.
  • WPF Fundamentals

    1. 1. Presenter Name Title Microsoft Corporation
    2. 3. Overview <ul><li>Application Model </li></ul><ul><li>Property System </li></ul><ul><li>Events </li></ul><ul><li>Commands </li></ul><ul><li>Threading </li></ul><ul><li>Animation </li></ul>
    3. 5. Application Model <ul><li>Application Class </li></ul><ul><li>Types of Application </li></ul><ul><li>Windows Application </li></ul><ul><li>XAML Browser Application </li></ul>
    4. 6. Application Class <ul><li>Core of the WPF Application model </li></ul><ul><ul><li>Serves as a container for WPF applications </li></ul></ul><ul><ul><li>Enables data to be shared </li></ul></ul><ul><li>Provides Application Events </li></ul><ul><li>Provides Windows Message Dispatching </li></ul><ul><li>Supports Navigation Between Pages </li></ul>
    5. 7. Application Class WM_PAINT WM_MOUSEMOVE
    6. 8. Windows Application <ul><li>Two types of Windows applications: </li></ul><ul><ul><li>Window-derived </li></ul></ul><ul><ul><li>NavigationWindow-derived </li></ul></ul>
    7. 9. <ul><li>WPF applications can be hosted within an internet browser </li></ul><ul><ul><li>Internet Explorer 6.0 & 7.0(.NET 3.0/3.5) </li></ul></ul><ul><ul><li>Mozilla Firefox (.NET 3.5 only) </li></ul></ul>XAML Browser Application <ul><li>Unified programming model </li></ul><ul><ul><li>Windowed apps and XBAPs are built using the same programming model </li></ul></ul><ul><ul><li>Graphics, Media, and Documents are all supported within this single model </li></ul></ul>
    8. 10. XAML Browser Application <ul><li>Partial Trust </li></ul><ul><ul><li>Available: Browser window, isolated storage, commands, 2-D and 3-D graphics, animation, media, audio, video, and more </li></ul></ul><ul><ul><li>Not available: Application-defined windows and dialog boxes, file system access, registry access, WinForms interop, and more </li></ul></ul><ul><li>Deployment </li></ul><ul><ul><li>ClickOnce, XCopy or MSI </li></ul></ul><ul><ul><li>Installed or live running </li></ul></ul>
    9. 12. Trees <ul><li>Element Trees </li></ul><ul><li>Logical Tree </li></ul><ul><li>Visual Tree </li></ul>
    10. 13. Element Tree Hierarchy <ul><li>The composition of elements creates a couple of hierarchical trees </li></ul><ul><ul><li>Logical Tree </li></ul></ul><ul><ul><li>Visual Tree </li></ul></ul><ul><li>There is an additional tree in WPF called the automation tree, but we won’t cover that in this session </li></ul>
    11. 14. Logical Tree <ul><ul><ul><li>The logical tree is composed of the elements that are explicitly listed in the XAML </li></ul></ul></ul><ul><ul><ul><li>The leaves of the logical tree may also be non-visual objects (CLR objects) </li></ul></ul></ul><ul><ul><ul><ul><li>The content of a ContentControl </li></ul></ul></ul></ul><ul><ul><ul><ul><li>The items of an ItemsControl </li></ul></ul></ul></ul>
    12. 15. Visual Tree <ul><ul><ul><li>The visual tree is composed of the visuals used to represent the logical tree </li></ul></ul></ul><ul><ul><ul><li>This includes all inflated control and data templates for elements in the logical tree </li></ul></ul></ul>
    13. 16. Visual & Logical Tree
    14. 17. Tree Traversal <ul><li>Logical Tree Traversal </li></ul><ul><ul><li>The LogicalTreeHelper class provides several methods for traversing the logical tree </li></ul></ul><ul><ul><li>LogicalTreeHelper is not needed very often in practice because most controls have properties exposing their logical children </li></ul></ul>
    15. 18. Tree Traversal, cont. <ul><li>Visual Tree Traversal </li></ul><ul><ul><li>The VisualTreeHelper class provides methods needed for traversing the visual tree </li></ul></ul><ul><ul><li>Although the Windows SDK indicates you won’t need to use VisualTreeHelper very often, in practice you will probably use it regularly </li></ul></ul>
    16. 19. Resolving via trees <ul><li>Resource resolution favors logical tree </li></ul><ul><li>Property Inheritance favors logical tree </li></ul><ul><li>Events route through the visual tree </li></ul>
    17. 21. Property System <ul><li>Dependency Properties </li></ul><ul><li>Dependency Property Value Precedence </li></ul><ul><li>Creating Dependency Properties </li></ul><ul><li>Attached Properties </li></ul><ul><li>Dependency Property Metadata </li></ul><ul><li>Inherited Dependency Properties </li></ul>
    18. 22. Dependency Properties <ul><li>The heart of the WPF property system </li></ul><ul><li>Enable most of the WPF features </li></ul><ul><ul><li>Data Binding </li></ul></ul><ul><ul><li>Styling </li></ul></ul><ul><ul><li>Attached Properties </li></ul></ul><ul><ul><li>Animation </li></ul></ul><ul><ul><li>Property Invalidation </li></ul></ul><ul><ul><li>Property Inheritance </li></ul></ul><ul><ul><li>Default Values </li></ul></ul><ul><ul><li>Sparse Storage </li></ul></ul>
    19. 23. Dependency Properties Exposes Dependency Properties Consumes Dependency Properties Does not have to derive from DependencyObject Derives from DependencyObject DependencyObject CustomClassA CustomClassB
    20. 24. Dependency Property Value Precedence <ul><li>Validation </li></ul><ul><li>Property coercion </li></ul><ul><li>Animations </li></ul><ul><li>Local value </li></ul><ul><li>Style triggers </li></ul><ul><li>Template triggers </li></ul><ul><li>Style setters </li></ul><ul><li>Theme style triggers </li></ul><ul><li>Theme style setters </li></ul><ul><li>Property value inheritance </li></ul><ul><li>Default value </li></ul>
    21. 25. Creating Dependency Properties <ul><li>Inherit from DependencyObject </li></ul><ul><li>Call DependencyObject.Register </li></ul><ul><li>Create standard .NET Framework property </li></ul>
    22. 26. Attached Properties <ul><li>Inherit from DependencyObject </li></ul><ul><li>Call DependencyProperty.RegisterAttach </li></ul><ul><li>Create two static methods Get nnn /Set nnn </li></ul>
    23. 27. Dependency Property Metadata
    24. 28. Dependency Properties <ul><li>The FrameworkPropertyMetadata class enables the setting of metadata for a property; an instance of this class should be passed when registering the property, be it attached or just a simple dependency property. </li></ul>
    25. 29. Inherited Dependency Properties <ul><li>Inherited by using the logical tree </li></ul><ul><li>Disabled by default (performance reasons) </li></ul><ul><li>Must be an AttachedDependencyProperty </li></ul><ul><li>Favors the logical tree </li></ul><ul><li>If an element does not have a logical parent, its properties will be inherited </li></ul>
    26. 31. Events <ul><li>Direct Events </li></ul><ul><li>Tunneling Events </li></ul><ul><li>Bubbling Events </li></ul><ul><li>Routed Events </li></ul><ul><li>Raising and Handling Events </li></ul><ul><li>RoutedEventArgs </li></ul>
    27. 32. Direct Events <ul><ul><ul><li>Direct events only go to the originating element </li></ul></ul></ul><ul><ul><ul><li>Direct events behave like standard CLR events </li></ul></ul></ul><ul><ul><ul><ul><li>The difference is that you can trigger on direct events </li></ul></ul></ul></ul>
    28. 33. Direct Events :ListBox Bd:Border :ScrollViewer :Grid :Rectangle :ScrollContentPresenter :ItemsPresenter :VirtualizingStackPanel :ListBoxItem :ListBoxItem :ListBoxItem : AdornerLayer : ScrollBar : ScrollBar
    29. 34. Tunneling Events <ul><ul><ul><li>Tunneled events begin with the highest visual parent </li></ul></ul></ul><ul><ul><ul><li>Moves down through the visual tree </li></ul></ul></ul><ul><ul><ul><li>Tunneling events are, by convention, prefixed with the word “Preview” </li></ul></ul></ul>
    30. 35. Tunneling Events :ListBox Bd:Border :ScrollViewer :Grid :Rectangle :ScrollContentPresenter :ItemsPresenter :VirtualizingStackPanel :ListBoxItem :ListBoxItem :ListBoxItem :AdornerLayer :ScrollBar :ScrollBar
    31. 36. Bubbling Events <ul><ul><ul><li>Bubbled events begin with the source visual element </li></ul></ul></ul><ul><ul><ul><li>Moves up through the visual tree </li></ul></ul></ul>
    32. 37. Bubbling Events :ListBox Bd:Border :ScrollViewer :Grid :Rectangle :ScrollContentPresenter :ItemsPresenter :VirtualizingStackPanel :ListBoxItem :ListBoxItem :ListBoxItem :AdornerLayer :ScrollBar :ScrollBar
    33. 38. RoutedEventArgs <ul><li>Marking the event as “handled” will generally stop the routing of the event </li></ul><ul><ul><li>Set the Handled property on RoutedEventArgs to true </li></ul></ul><ul><ul><li>If the event is a preview event, this will also prevent raising the corresponding bubbling event </li></ul></ul><ul><li>Handlers can be registered to receive handled events also </li></ul>
    34. 39. RoutedEventArgs :ListBox Bd:Border :ScrollViewer :Grid :Rectangle :ScrollContentPresenter :ItemsPresenter :VirtualizingStackPanel :ListBoxItem :ListBoxItem :ListBoxItem :AdornerLayer :ScrollBar :ScrollBar
    35. 40. Raising and Handling Events <ul><li>A routed event may be raised on any element within the visual tree </li></ul><ul><li>A handler for the event may be attached to any element higher in the visual tree </li></ul><ul><li>Attached Events </li></ul><ul><ul><li>Neither the element on which it is raised nor the element on which it is handled &quot;own&quot; that event </li></ul></ul>
    36. 41. XAML <ul><li>The XAML language also defines a special type of event called an attached event. An attached event enables you to add a handler for a particular event to an arbitrary element. The element handling the event need not define or inherit the attached event, and neither the object potentially raising the event nor the destination handling instance must define or otherwise &quot;own&quot; that event as a class member. </li></ul><ul><li>The WPF input system uses attached events extensively. However, nearly all of these attached events are forwarded through base elements. The input events then appear as equivalent non-attached routed events that are members of the base element class. For instance, the underlying attached event Mouse..::.MouseDown can more easily be handled on any given UIElement by using MouseDown on that UIElement rather than dealing with attached event syntax either in XAML or code. </li></ul>
    37. 42. Raising and Handling Events :ListBox Bd:Border :ScrollViewer :Grid :Rectangle :ScrollContentPresenter :ItemsPresenter :VirtualizingStackPanel :ListBoxItem :ListBoxItem :ListBoxItem :AdornerLayer :ScrollBar :ScrollBar Event Handler
    38. 43. Attached Event Example <StackPanel Button.Click=&quot;CommonClickHandler&quot; > <Button Name=&quot;YesButton&quot;>Yes</Button> <Button Name=&quot;NoButton&quot; >No</Button> <Button Name=&quot;CancelButton&quot;>Cancel</Button> </StackPanel>
    39. 45. Commands <ul><li>Commands Overview </li></ul><ul><li>RoutedCommand </li></ul><ul><li>Framework Commands </li></ul><ul><li>Control Support for Commands </li></ul><ul><li>Custom Commands </li></ul>
    40. 46. Commands Overview <ul><li>Routed Commands </li></ul><ul><ul><li>Encapsulate an action as an object </li></ul></ul><ul><ul><li>Separate the action from the handling of the action </li></ul></ul><ul><li>Improved Designer/Developer workflow </li></ul><ul><ul><li>When controls support commands it enables designers to very easily wire the invoking of those actions to whatever UI element they deem necessary </li></ul></ul>
    41. 47. Commands <ul><li>Commands in WPF are a more abstract and loosely-coupled version of routed events. The core concept of commanding in WPF is that the action is separate from both the source and the implementation of the command. An example would be the Cut, Copy, and Paste commands; these commands can be executed from many sources, such as a button, a menu item or a keyboard shortcut, but the implementation for each of the commands could be a single event handler. </li></ul><ul><li>By abstracting the action, or command, from the object that acts as the source and the implementation improves the designer and developer workflow, as the designer can simply say that they want a specific action to occur and leave it to the developer to actually implement command behaviour. Alternatively a developer can define a behaviour and have the designer easily wire that up in the UI with commands. </li></ul>
    42. 48. Commands Overview Cut Command Copy Command Paste Command
    43. 49. Commands <ul><li>Commands in WPF are a more abstract and loosely-coupled version of routed events. The core concept of commanding in WPF is that the action is separate from both the source and the implementation of the command. An example would be the Cut, Copy, and Paste commands; these commands can be executed from many sources, such as a button, a menu item or a keyboard shortcut, but the implementation for each of the commands could be a single event handler. </li></ul><ul><li>By abstracting the action, or command, from the object that acts as the source and the implementation improves the designer and developer workflow, as the designer can simply say that they want a specific action to occur and leave it to the developer to actually implement command behaviour. Alternatively a developer can define a behaviour and have the designer easily wire that up in the UI with commands. </li></ul>
    44. 50. RoutedCommand <ul><li>Command (ICommand) </li></ul><ul><ul><li>action </li></ul></ul><ul><li>Command Source (ICommandSource) </li></ul><ul><ul><li>invoker of the action </li></ul></ul><ul><li>Command Target </li></ul><ul><ul><li>The object on which the command is executed </li></ul></ul><ul><ul><li>If unset, the command is raised on the element with keyboard focus </li></ul></ul><ul><li>Command Binding (CommandBinding) </li></ul><ul><ul><li>Maps the command logic to the command </li></ul></ul>
    45. 51. RoutedCommand ICommand ICommandSource Command Target UI connected to a Command by Designers or Developers Cut Command
    46. 52. Framework Commands <ul><li>MediaCommands </li></ul><ul><ul><li>Play, Pause, Select, Stop, more... </li></ul></ul><ul><li>ApplicationCommands </li></ul><ul><ul><li>Cut, Copy, Paste, Find, Help, more... </li></ul></ul><ul><li>NavigationCommands </li></ul><ul><ul><li>BrowseBack, BrowseForward, Refresh, more... </li></ul></ul><ul><li>ComponentCommands </li></ul><ul><ul><li>MoveDown, MoveLeft, ScrollToEnd, more... </li></ul></ul><ul><li>EditingCommands </li></ul><ul><ul><li>AlignCenter, ApplyFontSize, MergeCells, more... </li></ul></ul>
    47. 53. Framework Commands
    48. 54. Framework Commands <ul><li>WPF defines a large number of commands built into five classes. This saves the developer effort as they do not have to write commands for Cut, Copy, and Paste for example. Each command is exposed as a static property on the five command classes. </li></ul>
    49. 55. Control Support for Commands <ul><li>Several WPF classes support easy execution of routed commands: </li></ul><ul><ul><li>MenuItem </li></ul></ul><ul><ul><li>Button (by way of ButtonBase) </li></ul></ul><ul><li>Some WPF classes implement commands out of the box: </li></ul><ul><ul><li>TextBox </li></ul></ul><ul><ul><li>RichTextBox </li></ul></ul><ul><li>By using the Command property on MenuItem or any ButtonBase-derived class commands are automatically executed on the logical click of the element. </li></ul><ul><li>Some WPF controls ship with an implementation for some commands, for example the TextBox and RichTextBox controls both have implementations for the Cut, Copy, and Paste commands, by way of the ButtonBase class. </li></ul>
    50. 56. Input Bindings <ul><li>An input binding binds an input gesture to a command </li></ul><ul><ul><li>KeyGesture </li></ul></ul><ul><ul><li>MouseGesture </li></ul></ul>
    51. 57. <ul><li>Applications and controls can implement their own custom routed commands by using the ICommand interface: </li></ul><ul><li>Or by using the RoutedCommand: </li></ul>Custom Commands
    52. 58. Commanding <ul><li>Commanding in WPF does not assume the use of a RoutedCommand or RoutedUICommand base class. Therefore, creating custom commands simply requires the implementation of the ICommand interface. Or they can simply expose a property of type RoutedCommand or RoutedUICommand. </li></ul>
    53. 60. Threading <ul><li>Threading In WPF </li></ul><ul><li>Dispatcher </li></ul><ul><li>DispatcherObject </li></ul><ul><li>Invoke and BeginInvoke </li></ul><ul><li>Multiple UI Threads </li></ul><ul><li>Freezables </li></ul>
    54. 61. Threading In WPF <ul><li>Multiple independent threads in WPF </li></ul><ul><ul><li>The UI thread </li></ul></ul><ul><ul><li>The Render Thread </li></ul></ul><ul><li>WPF UI is single threaded in the sense that most UI objects can only be associated with one thread </li></ul><ul><ul><li>There are exceptions: </li></ul></ul><ul><ul><ul><li>Static classes </li></ul></ul></ul><ul><ul><ul><li>Freezables </li></ul></ul></ul>
    55. 62. Dispatcher <ul><li>The Dispatcher object is effectively the event loop for the UI thread </li></ul><ul><li>There is one Dispatcher instance per UI thread </li></ul><ul><ul><li>Dispatcher.UnhandledException is great for catching data-binding/styling issues. </li></ul></ul>
    56. 63. Dispatcher Each thread that creates UI objects needs and has affinity with a Dispatcher object. The Dispatcher owns the thread, the message loop and is responsible for dispatching to the appropriate handlers. Dispatcher Owns The Thread Owns the Message Loop Dispatches To Handlers
    57. 64. DispatcherObject <ul><li>Most WPF objects derive from DispatcherObject </li></ul>DispatcherObject Object Visual D ependencyObject
    58. 65. DispatcherObject <ul><li>DispatcherObject associates an object with a Dispatcher and gives you methods to ensure that calling threads have access to the object. </li></ul><ul><li>CheckAccess method: </li></ul><ul><ul><ul><ul><li>Returns a bool that indicates if access is allowed </li></ul></ul></ul></ul><ul><li>VerifyAccess method: </li></ul><ul><ul><li>Throws an exception if access is not allowed </li></ul></ul><ul><li>Custom controls must use the VerifyAccess method in public members to ensure that only UI threads access it. </li></ul><ul><ul><li>If you use dependency properties you don’t have to worry about doing this yourself in property setters (It is done within DependencyObject.SetValue </li></ul></ul>
    59. 66. Invoke and BeginInvoke <ul><li>Invoke and BeginInvoke are used to push events onto a Dispatcher’s queue </li></ul><ul><ul><li>The Dispatcher’s event queue is “free-threaded” so any thread can call Invoke and BeginInvoke </li></ul></ul><ul><li>These methods are typically used by background threads that need to communicate with the UI thread </li></ul><ul><li>These methods can also be used to queue work on the UI thread from the UI thread itself </li></ul>
    60. 67. Dispatcher Operation <ul><li>BeginInvoke returns a DispatcherOperation object which can be used to interact with the delegate when the delegate is in the event queue </li></ul><ul><li>The DispatcherOperation object can be used in several ways to interact with the specified delegate, such as: </li></ul><ul><ul><li>Changing the DispatcherPriority of the delegate as it is pending execution in the event queue </li></ul></ul><ul><ul><li>Removing the delegate from the event queue </li></ul></ul><ul><ul><li>Waiting for the delegate to return </li></ul></ul><ul><ul><li>Obtaining the value that the delegate returns after it is executed </li></ul></ul>
    61. 68. Dispatching Priorities <ul><li>The Dispatcher maintains a prioritized queue of work items for a specific thread </li></ul>Priority Processed Send Before other asynchronous operations. This is the highest priority Normal Normal priority. This is the typical application priority DataBind At the same priority as data binding Render At the same priority as rendering Loaded When layout and render has finished but just before items at input priority are serviced. Specifically this is used when raising the Loaded event Input Processed at the same priority as input Background After all other non-idle operations are completed Context Idle After background operations are completed ApplicationIdle Application is idle SystemIdle Processed when the system is idle Inactive Not processed
    62. 69. Multiple UI Threads <ul><li>In some scenarios it makes sense to have multiple UI threads in an application </li></ul><ul><ul><li>For example an MDI application where each document or window gets its own thread </li></ul></ul><ul><li>Each UI thread gets its own Dispatcher in this case </li></ul>
    63. 70. Coding UI Threads <ul><li>To create another UI thread, call the Dispatcher.Run static method on a new thread. </li></ul><ul><li>using System; </li></ul><ul><li>using System.Threading; </li></ul><ul><li>using System.Windows; </li></ul><ul><li>using System.Windows.Threading; </li></ul><ul><li>namespace MuiltpleUIThreads </li></ul><ul><li>{ </li></ul><ul><li>public partial class MainWindow : Window </li></ul><ul><li>{ </li></ul><ul><li>public MainWindow() </li></ul><ul><li>{ </li></ul><ul><li>InitializeComponent(); </li></ul><ul><li>this.Title = this.Dispatcher.GetHashCode().ToString(); </li></ul><ul><li>} </li></ul><ul><li>private void Button_Click(object sender, RoutedEventArgs e) </li></ul><ul><li>{ </li></ul><ul><li>Thread t = new Thread(new ThreadStart(NewUIThread)); </li></ul><ul><li>t.SetApartmentState(ApartmentState.STA); // All UI element must be on a STA thread. </li></ul><ul><li>t.Start(); </li></ul><ul><li>} </li></ul><ul><li>private void NewUIThread() </li></ul><ul><li>{ </li></ul><ul><li>MainWindow win = new MainWindow(); </li></ul><ul><li>win.Show(); </li></ul><ul><li>Dispatcher.Run(); // Start a new UI Thread. </li></ul><ul><li>} </li></ul><ul><li>} </li></ul><ul><li>} </li></ul>
    64. 71. Freezables <ul><li>Objects with two states: </li></ul><ul><ul><li>Frozen – shared across threads, no change notification, immutable </li></ul></ul><ul><ul><li>Unfrozen </li></ul></ul><ul><li>Inherits from Freezable </li></ul><ul><ul><li>Includes Brush, KeyFrame, Transform, Pen, Geometry,Drawing, ImageSource …. </li></ul></ul>
    65. 72. Freezables <ul><li>Freezable defines an object that has a modifiable state and a read-only (frozen) state. Classes that derive from Freezable provide detailed change notification, can be made immutable, and can clone themselves. </li></ul><ul><li>The Freezable class makes it easier to use certain graphics system objects and can help improve application performance. Examples of types that inherit from Freezable include the Brush, Transform, and Geometry classes; as they contain unmanaged resources, WPF must monitor these objects for modifications, and then update their corresponding unmanaged resources when there is a change. Even if the object is not actually modified, the system must still spend some of its resources monitoring the object, in case it does get changed it. Freezing an object tells WPF to stop monitoring the object for changes, and therefore provides a potential performance boost and removes the thread affinity for the object, so it can be used safely on many threads. </li></ul><ul><li>If the object subsequently needs to be modified it is possible to then clone the object into a new instance, which will be unfrozen. </li></ul>
    66. 74. Triggers <ul><li>There are three types of Triggers in WPF </li></ul><ul><ul><li>Property Triggers </li></ul></ul><ul><ul><li>Data Triggers </li></ul></ul><ul><ul><li>Event Triggers </li></ul></ul><ul><li>Triggers are implemented by using the Style.Triggers property </li></ul>
    67. 75. Property Triggers <ul><li>Used to monitor a DependencyProperty's value </li></ul><ul><li>This code demonstrates the changing of the FontWeight property by using a Trigger: </li></ul>
    68. 76. Data Triggers <ul><li>Data triggers are executed when the value of any property changes using data binding </li></ul><ul><li>This code shows a DataTrigger: </li></ul>
    69. 77. Event Triggers <ul><li>Event triggers are executed when a routed event occurs </li></ul><ul><li>The following code example shows an EventTrigger: </li></ul>
    70. 78. Presenter Name Title Microsoft Corporation

    ×