Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 88 trang
THÔNG TIN TÀI LIỆU
Cấu trúc
Programming WPF, Second Edition
Table of Contents
Forewords
First Edition
Second Edition
Preface
Who This Book Is For
How This Book Is Organized
What You Need to Use This Book
Conventions Used in This Book
Using Code Examples
How to Contact Us
Safari® Books Online
Ian’s Acknowledgments
Chris’s Acknowledgments
Hello, WPF
WPF from Scratch
Building Applications
WPF Applications
XAML
Editing XAML
XAML Browser Applications (XBAPs)
Content Models
XAML Property Element Syntax
Layout
Grid Layout
XAML Attached Property Syntax
Controls
Data Binding
XAML Markup Extensions
Data Templates
Dependency Properties
Resources
XAML Namespace Mapping Syntax
Styles
Animation
Control Templates
Graphics
3D
Documents and Printing
Where Are We?
Applications and Settings
Application Lifetime
Explicit Application Creation
Application Access
Implicit Application Creation
Top-Level Windows
Application Shutdown Modes
Application Events
Startup event
Activated and Deactivated events
DispatcherUnhandledException event
SessionEnding event
Exit event
Application Instancing
Single instance applications
Other Application Services
Application Deployment
Simple Publishing
The User Experience
WPF ClickOnce Specifics
Settings
Designing Settings
Using Settings
Integrating Settings with WPF
Where Are We?
Layout
Layout Basics
StackPanel
WrapPanel
DockPanel
Grid
Column Widths and Row Heights
Spanning Multiple Rows and Columns
Consistency Across Multiple Grids
UniformGrid
Canvas
Viewbox
Common Layout Properties
Width and Height
MinWidth, MaxWidth, MinHeight, and MaxHeight
HorizontalAlignment and VerticalAlignment
Margin
Padding
Visibility
FlowDirection
Panel.ZIndex
RenderTransform and LayoutTransform
When Content Doesn’t Fit
ScrollViewer
Scrollable Region and IScrollInfo
Custom Layout
Where Are We?
Input
Routed Events
Halting Event Routing
Determining the Target
Routed Events and Normal Events
Attached Events
Mouse Input
Mouse Input and Hit Testing
Mouse State
Keyboard Input
Keyboard State
Ink Input
Commands
Command Objects
Defining commands
Using commands in XAML
Input Bindings
Command Source
Command Bindings
Enabling and disabling commands
Command routing
Code-Based Input Handling Versus Triggers
Where Are We?
Controls
What Are Controls?
Buttons
Slider and Scroll Controls
ProgressBar
Text Controls
Label
ToolTip
GroupBox and Expander
List Controls
List View
Tree View
Menus
Toolbars
GridSplitter
Where Are We?
Simple Data Binding
Without Data Binding
Object Changes
UI Changes
Data Binding
Bindings
Implicit Data Source
Data Islands
Explicit Data Source
Binding to Other Controls
Value Conversion
Editable Value Conversion
Validation
Custom validation rules
Binding Path Syntax
Relative Sources
Update Source Trigger
Debugging Data Binding
Where Are We?
Binding to List Data
Binding to List Data
Current Item
Getting the current item
Navigating between items
List Data Targets
Display Members, Value Members, and Look-Up Bindings
Data Templates
Typed data templates
DataTemplates and the DataContext
List Changes
Sorting
Default Collection Views
Filtering
Grouping
Declarative Sorting and Grouping
Data Source Providers
Object Data Provider
Asynchronous data retrieval
Passing parameters
Binding to Relational Data
XML Data Source Provider
XML data islands
XML binding without the data source provider
Master-Detail Binding
Hierarchical Binding
Where Are We?
Styles
Without Styles
Inline Styles
Named Styles
The Target Type Attribute
Reusing Styles
Overriding Style Properties
Extending Styles
Setting Styles Programmatically
Element-Typed Styles
Element-Typed Styles and Derived Types
Data Templates and Styles
Data Templates Redux
Data Templates with Style
Triggers
Property Triggers
Multiple Triggers
Multicondition Property Triggers
Data Triggers
Multicondition Data Triggers
Event Triggers
Where Are We?
Control Templates
Beyond Styles
Control Templates and Styles
Template Binding
Content Presenters
Template Triggers
Extending Templates
Repurposing an existing property
Defining a custom dependency property
The Control Template Contract
Property binding
Named parts
Content placeholders
Placeholders indicated by properties
Special-Purpose Elements
Examining the Built-in Templates
Logical and Visual Trees
Data-Driven UI
Where Are We?
Windows and Dialogs
Window
Window Look and Feel
Window Lifetime
Window Location and Size
Window Owners
Window Visibility and State
Dialogs
Common Dialogs
Available common dialogs
Custom Dialogs
Dialog look and feel
Dialog data exchange
Handling OK and Cancel
Data validation
Modeless dialogs
Where Are We?
Navigation
NavigationWindow
Pages
Loose XAML
Fragment Navigation
Page Lifetime
Passing Data Between Pages
Page Functions
Frames
XBAPs
XBAP Publication and Deployment
Navigation to HTML
Where Are We?
Resources
Creating and Using Resources
Resource Scope
Defining custom system-scope resources
Using system-scope resources
Resource References
Reusing Drawings
Resources and Styles
Skins and Themes
Binary Resources
Binary Resources and the Application Class
Pack URIs
Global Applications
Building Localizable Applications with XAML
Where Are We?
Graphics
Graphics Fundamentals
Integration
Drawing Object Model
Resolution Independence
Scaling and rotation
Resolution, coordinates, and “pixels”
Shapes, Brushes, and Pens
Composition
Shapes
Base Shape Class
Rectangle
Ellipse
Line
Polyline
Polygon
Path
Bézier curves
Combining shapes
Path geometry text format
Bitmaps
Image
ImageSource
Creating Bitmaps
Bitmap Encoders and Decoders
Bitmap Effects
Brushes and Pens
Color
SolidColorBrush
LinearGradientBrush
RadialGradientBrush
ImageBrush, DrawingBrush, and VisualBrush
TileBrush
ImageBrush
DrawingBrush
VisualBrush
Pen
Transformations
Visual Layer Programming
Rendering On Demand
Where Are We?
Text and Flow Documents
Fonts and Text Styles
Common Text Properties
Fonts and Font Families
FontSize
Stretch
Style
Weight
Decorations
Text Trimming
Text Wrapping and Hyphenation
Text Alignment
Text and the User Interface
TextBlock
Label and AccessText
Flow Documents and Viewer Controls
Visual Layer Text
Glyph runs
FormattedText
Glyphs
Text Object Model
Inline
Run
Span
LineBreak
InlineUIContainer
Block
Paragraph
List
Table
Section
BlockUIContainer
Figures and Floaters
Images
Text and Data Binding
Coding with the Text Object Model
TextPointer
Typography
Where Are We?
Printing and XPS
XPS
Open Packaging Conventions
XPS Document Classes
FixedDocumentSequence
FixedDocument
FixedPage
Page sizing
Page content limitations
Fonts, bitmaps, and other resources
Generating XPS Output
Printing Fixed Documents
Printing Visuals
Printing with Document Paginators
Asynchronous Printing
XPS File Generation Features
Package-Level XPS API
Core Document Properties
Thumbnails
Hyperlinks
Compression
System.Printing
PrintQueue
PrintServer
PrintSystemJobInfo
PrintTicket and PrintCapabilities
PrintDialog
Media Description
Displaying Fixed Documents
Where Are We?
Animation and Media
Animation Fundamentals
Animation Types
IAnimatable
Triggers
Timelines
Hierarchy
Duration
Repetition
Filling
Speed
Keyframe Animations
Path Animations
Clocks and Control
Controlling Animations with Storyboards
Controlling Animations with Clocks
Transition Animations
Audio and Video
Simple Media Playback
Using MediaElement in Clock Mode
Slipping
Where Are We?
3D Graphics
3D Content in a 2D World
Cameras
Models
Geometry3D
Materials
DiffuseMaterial
SpecularMaterial
EmissiveMaterial
MaterialGroup
ModelVisual3D
Lights
AmbientLight
DirectionalLight
PointLight
SpotLight
Textures
Transforms
TranslateTransform3D
ScaleTransform3D
RotateTransform3D
Transform3DGroup
MatrixTransform3D
3D Data Visualization
Hit Testing
Where Are We?
Custom Controls
Custom Control Basics
Choosing a Base Class
Custom Functionality
Properties
Attached properties
Value change notification
Change notifications for property consumers
Property metadata options
Events
Attached events
Commands
Supporting Templates in Custom Controls
Property Binding
Named Parts
Content Placeholders
Placeholders Indicated by Properties
Default Styles
UserControl
Adorners
AdornerDecorator
Where Are We?
XAML
XAML Essentials
Namespaces
Generating Classes
Properties
Children
Properties
Property Element Syntax
Attached Properties
Attached properties and the property element syntax
Markup Extensions
Built-in Markup Extensions
NullExtension
TypeExtension
ArrayExtension
StaticExtension
StaticResourceExtension
DynamicResourceExtension
ComponentResourceKey
Binding
RelativeSource
TemplateBindingExtension
Code Behind
Code in XAML
Loading XAML
Parsing XAML at Runtime
Loading Compiled XAML (BAML)
Interoperability
WPF and HWNDs
Hosting a Windows Form Control in WPF
Hosting a WPF Control in Windows Forms
Hosting WPF in Native HWND Apps
WPF and ActiveX Controls
WPF and HTML
Limitations of WPF/HWND Interop
Airspace
Transforms, Events, and Nested Interop
Asynchronous and Multithreaded WPF Programming
The WPF Threading Model
DispatcherObject
The Dispatcher
Obtaining a Dispatcher
Getting Onto the Right Thread with a Dispatcher
DispatcherOperation
DispatcherTimer
Multiple UI Threads and Dispatchers
The Event-Based Asynchronous Pattern
BackgroundWorker
WPF Base Types
DispatcherObject
DependencyObject
Visual
Visual3D
UIElement
FrameworkElement
Decorator
Panel
Shape
Control
ContentControl
HeaderedContentControl
UserControl
ItemsControl
HeaderedItemsControl
Selector
ContentElement
FrameworkContentElement
Freezable
Animatable
Silverlight
Why Silverlight?
What Is Silverlight?
Hello, Silverlight
Silverlight XAML
Layout Model
Namespaces
Graphics
Mouse Cursors
Measuring Text
Transformations
Animations
Silverlight and WPF
Development Model
Hosting in HTML
End-User Installation
Handling XAML Errors
Event Model
Working with XAML Properties
The Plug-in
Working with the XAML Object Model
An Example: Creating a Button
Creating Dynamic XAML
Controlling Media
Controlling Animations
Controlling animation execution
Delaying storyboards
Mixing Silverlight and HTML
The Silverlight Downloader
ASP.NET and Silverlight
Commingling with ASP.NET
Dynamic XAML
XAML and User Controls
A Taste of Silverlight 1.1
Tool Support
Expression Toolset
Expression Design
Expression Blend
Expression Media
Visual Studio
Other Tools
Examples in the World
Where Are We?
Index
Color Plates
Nội dung
238 | Chapter 7: Binding to List Data view.MoveCurrentToNext( ); if( view.IsCurrentAfterLast ) { view.MoveCurrentToLast( ); } } void addButton_Click(object sender, RoutedEventArgs e) { // Creating a new PeopleRow DataSourceProvider provider = (DataSourceProvider)this.FindResource("Family"); AdoBinding.Family.PeopleDataTable table = (AdoBinding.Family.PeopleDataTable)provider.Data; table.AddPeopleRow("Chris", 37); } void sortButton_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView( ); if( view.SortDescriptions.Count == 0 ) { view.SortDescriptions.Add( new SortDescription("Name", ListSortDirection.Ascending)); view.SortDescriptions.Add( new SortDescription("Age", ListSortDirection.Descending)); } else { view.SortDescriptions.Clear( ); } } void filterButton_Click(object sender, RoutedEventArgs e) { // Can't set the Filter property, but can set the // CustomFilter on a BindingListCollectionView BindingListCollectionView view = (BindingListCollectionView)GetFamilyView( ); if( string.IsNullOrEmpty(view.CustomFilter) ) { view.CustomFilter = "Age > 25"; } else { view.CustomFilter = null; } } void groupButton_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView( ); if( view.GroupDescriptions.Count == 0 ) { // Group by age view.GroupDescriptions.Add(new PropertyGroupDescription("Age")); } else { view.GroupDescriptions.Clear( ); } } } Example 7-38. Accessing the data held by ADO.NET (continued) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Data Source Providers | 239 In Example 7-38, you’ll notice that manipulating and displaying a person is different because we’re dealing with a DataRowView object’s Row property to get the typed PeopleRow we want. Also, adding a new person is different because we’re dealing with a PeopleDataTable. Finally, filtering is different because the BindingListCollectionView doesn’t support the Filter property (setting it causes an exception at runtime). How- ever, we set the CustomFilter string on the BindingListCollectionView using the ADO. NET filter syntax. Everything else, though—including accessing the collection view, navigating the rows, and even sorting and grouping—is the same, as shown in Figure 7-20. So, although there was no relational data-specific data provider, none is needed—the object data provider works just fine for data binding to relational data in WPF. XML Data Source Provider In addition to object and relational data, WPF also supports binding to XML data. For instance, Example 7-39 shows some family data represented in XML. With this file available in the same folder as the executing application, we can bind to it using the XmlDataProvider, as shown in Example 7-40. Figure 7-20. ADO.NET data binding in action Example 7-39. A random family rendered in XML <Family xmlns="http://sellsbrothers.com"> <Person Name="Tom" Age="11" /> <Person Name="John" Age="12" /> <Person Name="Melissa" Age="38" /> </Family> Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 240 | Chapter 7: Binding to List Data The first thing I want to point out in Example 7-40 is the use of the XmlDataProvider with a relative URL that points to the family.xml file. The first thing you’ll probably notice, though, is the large amount of XAML to deal with namespaces. Looking back at the XML file (Example 7-39), you’ll notice that no prefix was used, only a default namespace of http://sellsbrothers.com. Using namespace prefixes in the XAML makes it possible to construct the XPath statement to find the set of Person elements in our sam- ple XML. Finally, notice the use of the XPath property in the Binding objects instead of the Path property, and the @ symbol to designate binding to an XML attribute. * Example 7-40. An XmlDataProvider in action <! Window1.xaml > <Window > <Window.Resources> <XmlDataProvider x:Key="Family" Source="family.xml" XPath="/sb:Family/sb:Person"> <XmlDataProvider.XmlNamespaceManager> <XmlNamespaceMappingCollection> <XmlNamespaceMapping Uri="http://sellsbrothers.com" Prefix="sb" /> </XmlNamespaceMappingCollection> </XmlDataProvider.XmlNamespaceManager> </XmlDataProvider> <local:AgeToForegroundConverter x:Key="ageConverter" /> </Window.Resources> <Grid DataContext="{StaticResource Family}"> <ListBox ItemsSource="{Binding}"> <ListBox.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding XPath=@Name}" /> <TextBlock Text=" (age: " /> <TextBlock Text="{Binding XPath=@Age}" Foreground="{Binding XPath=@Age, Converter= {StaticResource ageConverter}}" /> <TextBlock Text=")" /> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Window> * An explanation of the XPath syntax is beyond the scope of this book, but for a good reference, I’d start with Essential XML Quick Reference, by Aaron Skonnard and Martin Gudgin (Addison-Wesley Professional). Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Data Source Providers | 241 XML data islands If you happen to know your data at compile time, the XML data provider also sup- ports XML data islands, as shown in Example 7-41. In Example 7-41, we’ve copied the contents of family.xml under the XmlDataProvider element and wrapped it in an XData element to designate it as separate from the rest of how XAML is parsed (Appendix A is a good place to read up on that topic). We’ve also dropped the Source attribute (because the data is embedded), but left the XPath statement as it was. And as you might expect, now that we’re using XML instead of object data, some of the operations in our sample application need to be changed (see Example 7-42). Example 7-41. An XML data island in XAML <XmlDataProvider x:Key="Family" XPath="/sb:Family/sb:Person"> <XmlDataProvider.XmlNamespaceManager> <XmlNamespaceMappingCollection> <XmlNamespaceMapping Uri="http://sellsbrothers.com" Prefix="sb" /> </XmlNamespaceMappingCollection> </XmlDataProvider.XmlNamespaceManager> <x:XData> <Family xmlns="http://sellsbrothers.com"> <Person Name="Tom" Age="11" /> <Person Name="John" Age="12" /> <Person Name="Melissa" Age="38" /> </Family> </x:XData> </XmlDataProvider> Example 7-42. Managing XML bound data // Window1.xaml.cs using System.Xml; public partial class Window1 : Window { public Window1( ) { InitializeComponent( ); this.birthdayButton.Click += birthdayButton_Click; this.backButton.Click += backButton_Click; this.forwardButton.Click += forwardButton_Click; this.addButton.Click += addButton_Click; this.sortButton.Click += sortButton_Click; this.filterButton.Click += filterButton_Click; this.groupButton.Click += groupButton_Click; } Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 242 | Chapter 7: Binding to List Data ICollectionView GetFamilyView( ) { DataSourceProvider provider = (DataSourceProvider)this.FindResource("Family"); return CollectionViewSource.GetDefaultView(provider.Data); } void birthdayButton_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView( ); // Each "person" is an XmlElement and attribute // values come from a string-based indexer XmlElement person = (XmlElement)view.CurrentItem; person.SetAttribute("Age", (int.Parse(person.Attributes["Age"].Value) + 1).ToString( )); MessageBox.Show( string.Format( "Happy Birthday, {0}, age {1}!", person.Attributes["Name"].Value, person.Attributes["Age"].Value), "Birthday"); } void backButton_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView( ); view.MoveCurrentToPrevious( ); if( view.IsCurrentBeforeFirst ) { view.MoveCurrentToFirst( ); } } void forwardButton_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView( ); view.MoveCurrentToNext( ); if( view.IsCurrentAfterLast ) { view.MoveCurrentToLast( ); } } void addButton_Click(object sender, RoutedEventArgs e) { // Creating a new XmlElement XmlDataProvider provider = (XmlDataProvider)this.FindResource("Family"); XmlElement person = provider.Document.CreateElement("Person", "http://sellsbrothers.com"); person.SetAttribute("Name", "Chris"); person.SetAttribute("Age", "37"); provider.Document.ChildNodes[0].AppendChild(person); } Example 7-42. Managing XML bound data (continued) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Data Source Providers | 243 Whereas in the ADO.NET example we used PeopleDataTable, PeopleDataRow, and DataRowView, in the XML example we use XmlDocument and XmlElement. For updating and accessing values, Example 7-42 uses the XmlElement SetAttribute method to change a value and the Attributes collection to get one. When adding a new person, we get the XmlDocument from the XmlDataProvider, ask it to create a new XmlElement, set the attributes, and add it to the child node collection of the document. When filtering, we simply cast to an XmlElement to access the attributes we need to make filter- ing decisions. Finally, when sorting or grouping, the descriptions include paths as XPath expressions (e.g., @Age). The results look just like Figure 7-20. void sortButton_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView( ); if( view.SortDescriptions.Count == 0 ) { view.SortDescriptions.Add( new SortDescription("@Name", ListSortDirection.Ascending)); view.SortDescriptions.Add( new SortDescription("@Age", ListSortDirection.Descending)); } else { view.SortDescriptions.Clear( ); } } void filterButton_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView( ); if( view.Filter == null ) { view.Filter = delegate(object item) { return int.Parse(((XmlElement)item).Attributes["Age"].Value) > 25; }; } else { view.Filter = null; } } void groupButton_Click(object sender, RoutedEventArgs e) { ICollectionView view = GetFamilyView( ); if( view.GroupDescriptions.Count == 0 ) { // Group by age view.GroupDescriptions.Add(new PropertyGroupDescription("@Age")); } else { view.GroupDescriptions.Clear( ); } } } Example 7-42. Managing XML bound data (continued) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 244 | Chapter 7: Binding to List Data XML binding without the data source provider If you’ve already got a source of XML data that isn’t readily available for use by the XML data source provider, * you can programmatically bind to it instead, as shown in Example 7-43. * For example, if you need to retrieve XML data via an HTTP POST, you can’t use the XML data source pro- vider, as it can only use HTTP GET. Example 7-43. XML binding without the data source provider <! Window1.xaml > <Window > <Window.Resources> <! no XmlDataProvider > <local:AgeToForegroundConverter x:Key="ageConverter" /> </Window.Resources> <! DataContext set in code-behind > <Grid Name="grid"> </Grid> </Window> // Window1.xaml.cs public partial class Window1 : Window { // the family XML document XmlDocument doc; public Window1( ) { LoadFamilyXml( ); } void LoadFamilyXml( ) { // Load the XML using an XmlDocument doc = new XmlDocument( ); doc.Load("family.xml"); // Make the namespace prefix mappings available for use in binding XmlNamespaceManager manager = new XmlNamespaceManager(doc.NameTable); manager.AddNamespace("sb", "http://sellsbrothers.com"); Binding.SetXmlNamespaceManager(grid, manager); // Make the XML available for data binding. We use a binding here // because it will detect when the source document changes so it can // refresh the set of nodes returned by the XPath query Binding b = new Binding( ); b.XPath = "/sb:Family/sb:Person"; b.Source = doc; grid.SetBinding(Grid.DataContextProperty, b); } Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Master-Detail Binding | 245 In Example 7-43, we’re loading the XML manually from a file, but you can get access to the XML in whatever way is convenient, as long as you have an XmlNode or XmlNodeList to which to bind. Here we’re creating the XmlDocument as a member variable so that we can use it again to create and add a new XmlElement in the addButton_Click event handler. Notice also that we’re populating an XmlNamespaceManager and binding it to the grid so that binding knows how to trans- late XPath strings that use namespace prefixes. And finally, instead of setting the XML data directly as the grid’s DataContext, we’re actually binding it, along with the XPath to filter the set of nodes available in the XML data. The binding is there so that when the underlying XML data changes, resulting in a new set of nodes returned from the XPath expression, the grid’s data context is updated appropriately. Also, as this data context changes, the view may change, so we’re using the DataContext property of the grid to get the view in GetFamilyView each time we need it. The rest of the XML-related code in this sample does not have to change, as we’ve just done manually what the XML data source provider was doing for us (although we did leave out support for asynchronous access to the data, if it happens to be far away). Master-Detail Binding We’ve seen binding to a single object. We’ve seen binding to a single list of objects. Another very popular thing to do is to bind to more than one list, especially related lists. For example, if you’re showing your users a list of customers and then, when they select one, you’d like to show that customer’s related orders, you’ll want master-detail binding. ICollectionView GetFamilyView( ) { // The default view comes directly from the data return CollectionViewSource.GetDefaultView(grid.DataContext); } void addButton_Click(object sender, RoutedEventArgs e) { // Creating a new XmlElement XmlElement person = doc.CreateElement("Person", "http://sellsbrothers.com"); person.SetAttribute("Name", "Chris"); person.SetAttribute("Age", "37"); doc.DocumentElement.AppendChild(person); } } Example 7-43. XML binding without the data source provider (continued) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 246 | Chapter 7: Binding to List Data Master-detail binding is a form of filtering, where the selection in the master list (e.g., customer 452) sets the filtering parameters for the associated detail data (e.g., orders for customer 452). In our discussion thus far, we don’t have customers and orders, but we do have fami- lies and people, which we could further formalize as shown in Example 7-44. In Example 7-44, we’ve got our familiar Person class with Name and Age properties, collected into a familiar People collection. Further, we have a Family class with a FamilyName property and a Members property of type People. Finally, we have a Families collection, which collects Family objects. In other words, families have members, which consist of people with names and ages. You could imagine instances of Families, Family, People, and Person that looked like Figure 7-21. Example 7-44. Master-detail data for binding public class Person { string name; public string Name { get { return name; } set { name = value; } } int age; public int Age { get { return age; } set { age = value; } } } public class People : ObservableCollection<Person> {} public class Family { string familyName; public string FamilyName { get { return familyName; } set { familyName = value; } } People members; public People Members { get { return members; } set { members = value; } } } public class Families : ObservableCollection<Family> {} Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Master-Detail Binding | 247 In Figure 7-21, the Families collection forms the master data, holding instances of the Family class, each of which holds a Members property of type People, which holds the detail Person data. You could populate instances of these data structures as shown in Example 7-45. Figure 7-21. Example master-detail data Example 7-45. Declaring example master-detail data <! Window1.xaml > <Window xmlns:local="clr-namespace:MasterDetailBinding"> <Window.Resources> <local:Families x:Key="Families"> <local:Family FamilyName="Stooge"> <local:Family.Members> <local:People> <local:Person Name="Larry" Age="21" /> <local:Person Name="Curly" Age="22" /> <local:Person Name="Moe" Age="23" /> </local:People> </local:Family.Members> </local:Family> Family .Name = "Stooges" .Members Family .Name = "Addams" .Members Families (Master) Person .Name = "Larry" .Age = 21 Person .Name = "Moe" .Age = 23 People (Details) Person .Name = "Curly" .Age = 22 Person .Name = "Gomez" .Age = 135 Person .Name = "Morticia" .Age = 121 People (Details) Person .Name = "Fester" .Age = 137 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com [...]... are things that WPF s data binding engine supports that we haven’t discussed (some of which we’ll get to in the next chapter, but some of which are beyond the scope of this book*) The thorough support for data binding at every level of WPF makes it a first-class feature in a way that data binding has never been before You’ll find that it permeates pretty much every aspect of your WPF programming, including... nicer-looking tic-tac-toe board Inline Styles A style in WPF is expressed as zero or more Setter objects inside a Style object Every element in WPF that derives from either FrameworkElement or FrameworkContentElement has a Style property, which you can set inline using standard XAML property element syntax, as shown in Example 8 -4 Example 8 -4 Setting an inline style ... Expanding our XAML a bit to include traits would look like Example 7 -49 Example 7 -49 Declaring a third level of detail 250 | Chapter 7: Binding to List Data Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Example 7 -49 Declaring a third level of detail (continued) WPF, a style is also a set of properties... binding for the next level To see this in action, let’s add one more level of detail to our data classes (see Example 7 -48 ) Master-Detail Binding | 249 Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com Figure 7-23 Showing master Family and detail Person data Example 7 -48 Adding a third level of detail public class Person { string name; public string Name { get { return name; } set... control Our element-typed styles return our game to looking again like Figure 8 -4 Element-typed styles are handy whenever you’d like all instances of a certain element to share a look, depending on the scope For example, we’ve scoped the button style in our sample thus far at the top-level Window (see Example 8- 14) Example 8- 14 Style scoped to the Window Binding to this data at the top level (i.e., to show the family names) could look like Example 7 -46 Example 7 -46 Binding to master Family data . the family XML document XmlDocument doc; public Window1( ) { LoadFamilyXml( ); } void LoadFamilyXml( ) { // Load the XML using an XmlDocument doc = new XmlDocument( ); doc. Load("family.xml"); . customer 45 2). In our discussion thus far, we don’t have customers and orders, but we do have fami- lies and people, which we could further formalize as shown in Example 7 -44 . In Example 7 -44 , we’ve. view.GroupDescriptions.Clear( ); } } } Example 7 -42 . Managing XML bound data (continued) Simpo PDF Merge and Split Unregistered Version - http://www.simpopdf.com 244 | Chapter 7: Binding to List Data XML