This is automatically done by WPF! The only trick is assigning this Trigger to each Button. Unfortunately, because of an artificial limitation in WPF version 3. They can only be applied inside a Style object, so an in-depth examination of property triggers is saved for Chapter Unfortunately, this collection can only contain event triggers in version 3.
Attempting to add a property trigger or data trigger to the collection causes an exception to be thrown at run-time. A simple example of this can be seen in Listing 3. Notice that the Window automatically resizes to fit all the content thanks to its slick SizeToContent setting! A data trigger is a form of property trigger that works for all.
NET properties not just dependency properties , also covered in Chapter An event trigger enables you to declaratively specify actions to take when a routed event covered later in the chapter is raised. For the most part, these two settings flow all the way down the tree and are inherited by children. This affects even the Buttons and ListBoxItems, which are three levels down the logical tree.
Notice that the text in the StatusBar is unaffected by either of these values, despite the fact that it supports these two properties just like the other controls. The behavior of property value inheritance can be subtle in cases like this for two reasons:. Not every dependency property participates in property value inheritance. Internally, dependency properties can opt in to inheritance by passing FrameworkPropertyMetadataOptions.
Inherits to DependencyProperty. There may be other higher-priority sources setting the property value, as explained in the next section. In this case, the latter reason is to blame. A few controls such as StatusBar, Menu, and ToolTip internally set their font properties to match current system settings. This way, users get the familiar experience of controlling their font via Control Panel.
Without a well-defined mechanism for handling these disparate property value providers, the system would be a bit chaotic and property values could be unstable. Of course, as their name indicates, dependency properties were designed to depend on these providers in a consistent and orderly manner. This process happens automatically thanks to the built-in change notification in dependency properties.
Step 1: Determine Base Value Most of the property value providers factor into the base value calculation. The following list reveals the eight providers that can set the value of most dependency properties, in order from highest to lowest precedence: 1. Local value 5. Theme style triggers 2. Style triggers 6. Theme style setters 3. Template triggers 7. Property value inheritance 4. Style setters 8. Default value 3 Property value inheritance was originally designed to operate on the element tree, but it has been extended to work in a few other contexts as well.
Local value technically means any call to DependencyObject. SetValue, but this is typically seen with a simple property assignment in XAML or procedural code because of the way dependency properties are implemented, as shown previously with Button.
Default value refers to the initial value registered with the dependency property, which naturally has the lowest precedence. The other providers, which all involve styles and templates, are explained further in Chapter Although this has precedence over property value inheritance 7 in the list , you can still override these font settings using any mechanism with a higher precedence, such as simply setting local values on the StatusBar.
Step 2: Evaluate If the value from step one is an expression an object deriving from System. Expression , then WPF performs a special evaluation step to convert the expression into a concrete result.
In version 3. Future versions of WPF may enable additional kinds of expressions. Step 3: Apply Animations If one or more animations are running, they have the power to alter the current property value using the value after step 2 as input or completely replace it. Therefore, animations the topic of Chapter 13 can trump all other property value providers—even local values! This is often a stumbling block for people who are new to WPF.
Step 4: Coerce After all the property value providers have had their say, WPF takes the almost-final property value and passes it to a CoerceValueCallback delegate, if one was registered with the dependency property. The callback is responsible for returning a new value, based on custom logic. For example, built-in WPF controls such as ProgressBar use this callback to constrain its Value dependency property to a value between its Minimum and Maximum values, returning Minimum if the input value is less than Minimum or Maximum if the input value is greater than Maximum.
Step 5: Validate Finally, the potentially-coerced value is passed to a ValidateValueCallback delegate, if one was registered with the dependency property. This callback must return true if the input value is valid or false otherwise.
Returning false causes an exception to be thrown, cancelling the entire process. GetValueSource method as a debugging aid. This returns a ValueSource structure that contains a few pieces of data: a BaseValueSource enumeration that reveals where the base value came from step 1 in the process and Boolean IsExpression, IsAnimated, and IsCoerced properties that reveal information about steps Do not use this method in production code! If the theme is changed and the new theme tries to change the default Foreground color or if other providers with higher precedence try to do the same , it gets trumped by the local setting of black.
What you likely want to do instead is clear the local value and let WPF set the value from the relevant provider with the next-highest precedence. Fortunately, DependencyObject provides exactly this kind of mechanism with its ClearValue method. This can be called on a Button b as follows in C : b. ClearValue Button. ForegroundProperty ; Button. ForegroundProperty is the static DependencyProperty field.
After calling ClearValue, the local value is simply removed from the equation when WPF recalculates the base value. A trigger is either active or inactive, and when inactive it is simply ignored in the property value calculation.
Theme styles are sometimes referred to as default styles. The enumeration value for a theme style trigger is DefaultStyleTrigger. This may sound strange at first, but this mechanism has several applications in WPF. Instead, you must use the FontSize and FontStyle attached properties that happen to be defined on a class called TextElement.
Dependency Properties 61 TextElement. FontSize and TextElement. When a XAML parser or compiler encounters this syntax, it requires that TextElement sometimes called the attached property provider has static methods called SetFontSize and SetFontStyle that can set the value accordingly. Therefore, the StackPanel declaration in Listing 3.
Italic, Orientation. Horizontal, and HorizontalAlignment. This is possible thanks to the EnumConverter type converter in the. NET Framework, which can convert any case-insensitive string.
One of the interesting things about the attached property abstraction is that no. NET property is a part of it! SetValue TextElement. SetFontSize panel, 30 ; TextElement. SetFontStyle panel, FontStyles. Italic ; panel. Horizontal; panel. Add helpButton ; panel. GetValue TextElement. Instead, they are defined by the seemingly unrelated TextElement class and also by the TextBlock class, which could also be used in the preceding examples. How can this possibly work when TextElement.
FontSizeProperty and TextElement. FontStyleProperty is separate from Control. The key is the way these dependency properties are internally registered.
If you were to look at the source code for TextElement, you would see something like the following: TextElement. Inherits FrameworkPropertyMetadataOptions. Inherits ; Therefore, the FontSize, FontStyle, and other font-related dependency properties inherited by all controls are the same properties exposed by TextElement!
Fortunately, in most cases, the class that exposes an attached property e. Dependency Properties 63 Although the About dialog example uses attached properties for advanced property value inheritance, attached properties are most commonly used for layout of user interface elements. Various Panel-derived classes define attached properties designed to be attached to their children for controlling how they are arranged. This way, each Panel can apply its own custom behavior to arbitrary children without requiring all possible child elements to be burdened with their own set of relevant properties.
It also enables systems like layout to be easily extensible, because anyone can write a new Panel with custom attached properties. Object intended for storing arbitrary custom data with each instance. But attached properties are a more powerful and flexible mechanism for attaching custom data to any object deriving from DependencyObject. A further twist to the story of attached properties is that although setting them in XAML relies on the presence of the static SetXXX method, you can bypass this method in procedural code and call DependencyObject.
SetValue directly. This means that you can use any dependency property as an attached property in procedural code. SetValue ListBox. There are more interesting ways to extend elements in this manner.
SetValue FrameworkElement. NET properties, it also adds more infrastructure on top of the simple notion of. NET events. Routed events are events that are designed to work well with a tree of elements. When a routed event is raised, it can travel up or down the visual and logical tree, getting raised on each element in a simple and consistent fashion, without the need for any custom code.
When a user presses the left mouse button with the mouse pointer over a standard Button, however, they are really interacting with its ButtonChrome or TextBlock visual child.
Because the event travels up the visual tree, the Button eventually sees the event and can handle it. Similarly, for the VCR-style Stop Button in the preceding chapter, a user might press the left mouse button directly over the Rectangle logical child. Because the event travels up the logical tree, the Button still sees the event and can handle it as well.
Yet if you really wish to distinguish between an event on the Rectangle versus the outer Button, you have the freedom to do so. Therefore, you can embed arbitrarily complex content inside an element like Button or give it an arbitrarily complex visual tree using the techniques in Chapter 10 , and a mouse left-click on any of the internal elements still results in a Click event raised by the parent Button.
Without routed events, producers of the inner content or consumers of the Button would have to write code to patch everything together. The implementation and behavior of routed events have many parallels to dependency properties. As with dependency properties, no. Just as dependency properties are represented as public static DependencyProperty fields with a conventional Property suffix, routed events are represented as public static RoutedEvent fields with a conventional Event suffix.
The routed event is registered much like a dependency property in the static constructor, and a normal. NET event—or event wrapper—is defined to enable more familiar use from procedural code and adding a handler in XAML with event attribute syntax. As with a property wrapper, an event wrapper must not do anything in its accessors other than call AddHandler and RemoveHandler.
UIElement, a higher-level base class of elements such as Button. This class hierarchy is examined in more depth at the end of this chapter. These methods attach and remove a delegate to the appropriate routed event. The current Button instance this is passed as the source element of the event. These strategies are exposed as values of a RoutingStrategy enumeration:. Tunneling—The event is first raised on the root, then on each element down the tree until the source element is reached or until a handler halts the tunneling by marking the event as handled.
Bubbling—The event is first raised on the source element, then on each element up the tree until the root is reached or until a handler halts the bubbling by marking the event as handled. Direct—The event is only raised on the source element. This is the same behavior as a plain. NET event, except that such events can still participate in mechanisms specific to routed events such as event triggers.
Handlers for routed events have a signature matching the pattern for general. NET event handlers: The first parameter is a System. Object typically named sender, and the second parameter typically named e is a class that derives from System. The sender parameter passed to a handler is always the element to which the handler was attached. The e parameter is or derives from an instance of RoutedEventArgs, a subclass of EventArgs that exposes four useful properties:.
Source—The element in the logical tree that originally raised the event. OriginalSource—The element in the visual tree that originally raised the event for example, the TextBlock or ButtonChrome child of a standard Button. Handled—A Boolean that can be set to true to mark the event as handled. This is precisely what halts any tunneling or bubbling.
RoutedEvent—The actual routed event object such as Button. ClickEvent , which can be helpful for identifying the raised event when the same handler is used for multiple routed events. The presence of both Source and OriginalSource enable you to work with the higherlevel logical tree or the lower-level visual tree.
This distinction only applies to physical events like mouse events, however. Most of these are bubbling events, but many of them are paired with a tunneling event. Tunneling events can be easily identified because, by convention, they are named with a Preview prefix. These events, also by convention, are raised immediately before their Routed Events bubbling counterpart. In other The idea behind having a pair of events words, its use raises events such as for various activities is to give elements MouseMove, MouseDown, and MouseUp.
However, if you elements only take action in response to want to provide an experience that is optia bubbling event when a bubbling and mized for a stylus, you can handle stylustunneling pair is defined , ensuring that specific events such as StylusMove, the tunneling event lives up to its StylusDown, and StylusUp.
There are other ways to number or zip code. In this case, the TextBox will never receive the KeyDown notification and the current character will not get displayed. Input; System. Media; System. But what about the additional buttons present on some mice? This information can be retrieved via the more generic MouseDown and MouseUp events which also have Preview counterparts.
This can only be done from procedural code, using an overload of AddHandler that adds a Boolean handledEventsToo parameter. For example, the event attribute could be removed from Listing 3. AddHandler Window. You should avoid processing handled events whenever possible, because there is likely a reason the event is handled in the first place.
Attaching a handler to the Preview version of an event is the preferred alternative. The bottom line, however, is that the halting of tunneling or bubbling is really just an illusion. Attached Events The tunneling and bubbling of a routed event is natural when every element in the tree exposes that event. This is possible thanks to the notion of attached events. Attached events operate much like attached properties and their use with tunneling or bubbling is very similar to using attached properties with property value inheritance.
Both event handlers simply show a MessageBox with information about what just happened. Windows; using System. The attached event syntax used in Listing 3. NET event defined on Button. At run-time, however, AddHandler is directly called to attach these two events to the Window. AddHandler ListBox. AddHandler Button. This handler could examine the RoutedEvent object to determine which event got raised, cast the RoutedEventArgs parameter to an appropriate subclass such as KeyEventArgs, MouseButtonEventArgs, and so on and go from there.
For example, Listing 3. SelectionChanged and Button. Whereas events are tied to details about specific user actions such as a Button being clicked or a ListBoxItem being selected , commands represent actions independent from their user interface exposure. Canonical examples of commands are Cut, Copy, and Paste. You could handle the multiple exposures of commands such as Cut, Copy, and Paste with events fairly well.
For example, you could define a generic event handler for each of the three actions and then attach each handler to the appropriate events on the relevant elements the Click event on a Button, the KeyDown event on the main Window, and so on. The support reduces the amount of code you need to write and in some cases eliminating all procedural code , and it gives you more flexibility to change your user interface without breaking the back-end logic.
NET Framework, enabling a delegate to be used with a method whose signature uses a base class of an expected parameter e. GenericHandler simply casts the RoutedEventArgs parameter when necessary to get the extra information specific to the SelectionChanged event. WPF defines a number of built-in commands.
Commands have automatic support for input gestures such as keyboard shortcuts. Input , which defines three simple members:. Execute—The method that executes the command-specific logic. CanExecute—A method returning true if the command is enabled or false if it is disabled.
CanExecuteChanged—An event that is raised whenever the value of CanExecute changes If you want to create Cut, Copy, and Paste commands, you could define and implement three classes implementing ICommand, find a place to store them perhaps as static fields of your main Window , call Execute from relevant event handlers when CanExecute returns true , and handle the CanExecuteChanged event to toggle the IsEnabled property on the relevant pieces of user interface.
Fortunately, controls such as Button, CheckBox, and MenuItem have logic to interact with any command on your behalf.
They expose a simple Command property of type ICommand. In addition, they automatically keep their value for IsEnabled synchronized with the value of CanExecute by leveraging the CanExecuteChanged event. By supporting all this via a simple property assignment, all of this logic is available from XAML.
Instead, they are all instances of RoutedUICommand, a class that not only implements ICommand, but supports bubbling just like a routed event. Assuming the Button is named helpButton, you can associate it with the Help command in C as follows: helpButton. The hard-coded Content on this Button could therefore be replaced as follows: helpButton. Text; If you were to run the About dialog with this change, you would see that the Button is now permanently disabled.
They delegate this logic to consumers of the commands. To plug in custom logic, you need to add a CommandBinding to the element that will execute the command or any parent element thanks to the bubbling behavior of routed commands.
This means that a Button whose Content is assigned to ApplicationCommands. Even in a context where you want to expose images rather than text perhaps on a ToolBar , you can still leverage this localized string elsewhere, such as in a ToolTip. Leveraging Text on commands can simply cut down on the number of terms you need to translate.
Add new CommandBinding ApplicationCommands. Listings 3. Executing Commands with Input Gestures Using the Help command in such a simple dialog may seem like overkill when a simple event handler for Click would do, but the command has provided an extra benefit other than localized text : automatic binding to a keyboard shortcut. Applications typically invoke their version of help when the user presses the F1 key.
Sure enough, if you press F1 while displaying the dialog defined in Listing 3. Add new KeyBinding ApplicationCommands. Help, new KeyGesture Key. F2 ; This would make both F1 and F2 execute Help, however. You could additionally suppress the default F1 behavior by binding F1 to a special NotACommand command as follows: this.
The simplest example of this is the TextBox control, which has its own built-in bindings for the Cut, Copy, and Paste commands that interact with the clipboard, as well as Undo and Redo commands. The following standalone XAML demonstrates the power of these built-in command bindings: You can paste this content into XamlPad or save it as a. This causes the command to be executed from the TextBox rather than the Button, which is necessary in order for it to react to the commands.
The first two Buttons are automatically disabled when no text in the TextBox is selected, and automatically enabled when there is a selection. Similarly, the Paste Button is automatically enabled whenever there is text content on the clipboard, or disabled otherwise. Button and TextBox have no direct knowledge of each other, yet though commands they can achieve rich interaction. The inside cover of this book contains a map of these classes to help you put them in perspective as you encounter new ones.
It is incomplete due to space constraints, but the major classes are covered. A handful of classes are fundamental to the inner-workings of WPF, and deserve a quick explanation before we get any further in the book. Some of these have been mentioned in passing already. These ten classes have the following significance:. Object—The base class for all. NET classes.
DispatcherObject—The base class for any object that wishes to be accessed only on the thread that created it. DependencyObject—The base class for any object that can support dependency properties.
DependencyObject defines the GetValue and SetValue methods that are central to the operation of dependency properties. Freezables, once frozen, can even be safely shared among multiple threads, unlike all other DispatcherObjects. Frozen objects can never be unfrozen, but you can clone them to create unfrozen copies.
Visual—The base class for all objects that have their own visual representation. Visuals are discussed in depth in Chapter UIElement—The base class for all visual objects with support for routed events, command binding, layout, and focus.
Instead, ContentElements are hosted in a Visual-derived class to be rendered on the screen. FrameworkElement—The base class that adds support for styles, data binding, resources, and a few common mechanisms for Windows-based controls such as tooltips and context menus. Controls also support templates that enable you to completely replace their visual tree, discussed in Chapter Hopefully you can now appreciate some of the value of these new mechanisms.
Throughout the rest of the book, these concepts generally fade into the background as we focus on accomplishing specific development tasks. The WPF team could have exposed its features via typical. Instead, the team added several fundamental concepts that enable a wide range of features to be exposed in a way that can provide great productivity for developers and designers.
Most WPF controls contain several distinct default appearances, however. Aero the default Windows Vista theme. Luna the default Windows XP theme. Classic the theme available in Windows and later For example, Figure 4. Items Controls. Range Controls. In most cases, the difference in appearance is very subtle. Content Controls. Text and Ink Controls Content Controls Content controls are simply controls that are constrained to contain a single item. Content controls all derive from System.
There just can only be one direct child. This simply returns false if Content is null, or true otherwise. From a C perspective, the HasContent property is redundant. But from a XAML perspective, the property is useful. For example, it makes it easy to use a property trigger to set various property values when HasContent becomes true. The way it works is fairly simple. This book is for software developers who are interested in user interfaces. At the very least, it should be an invaluable reference for your bookshelf.
Because WPF enables you to create not only standalone Windows applications but also content hosted in a web browser, anyone interested in alternatives to Adobe Flash might find this book interesting. To summarize, this book. Examines the WPF feature areas in incredible depth: controls, layout, resources, data binding, styling, graphics, animation, and more. IronRuby Unleashed thoroughly illuminates the use of IronRuby and. NET code, and create.
NET code libraries that fit well with IronRuby code. Full color: Learn how to build great Windows Store apps! Figures and code appear as they do in Visual Studio. Windows 8. You can sell them in the Windows Store, with more options than ever before, for tablets such as Surface, laptops, and traditional desktop PCs! World-renowned Microsoft programming guru Adam Nathan shows you exactly how to write first-class apps for this significant update to Windows.
Writing with unprecedented depth and insight, Nathan guides you through creating advanced user interfaces with XAML and exploiting key Windows 8. Use XAML to represent state-of-the-art user interfaces, even across multiple windows Handle touch, mouse, keyboard, and pen input, including handwriting recognition Use new Windows 8.
Printed entirely in color, with helpful figures and syntax coloring to make code samples appear as they do in Visual Studio and Expression Blend! Using Silverlight 4, you can build richer and more powerful applications than ever before, and deploy them seamlessly in browsers, on desktop computers, and even on Windows Phone 7.
The only full-color, example-rich guide to Silverlight 4 for experienced Microsoft developers, Silverlight 4 Unleashed illuminates the entire development process: from installing Silverlight tools to building great user experiences, managing data to optimizing application performance.
0コメント