Migrate .NET 3.1/5 WPF guide from dotnet docs (#48)

* add toc/bread changes

* add xaml-services

* add ported wpf content

* add xaml-services info to docfx

* Fix links 1

* Fix links 2

* Fix links 3

* Fix links 4

* Fix links 5

* Fix links 6

* Fix links 7

* Fix xaml-services link

* Fix snippets 1

* Fix snippets 2

* adjust breadcrumb and toc

* remove preserve-view from breadcrumbs

* add empty view to toc item xaml

* update include

* remove contextual toc for vs article :(
This commit is contained in:
Andy De George
2020-09-17 08:41:01 -07:00
committed by GitHub
parent 57747b5d52
commit 9371b0126b
220 changed files with 8961 additions and 17 deletions
+4 -1
View File
@@ -9,6 +9,9 @@ items:
- name: Windows Presentation Foundation
expanded: true
items:
- name: ".NET 5 (and .NET Core 3.1)"
href: net/wpf/index.yml?view=netdesktop-5.0&preserve-view=true
- name: .NET Framework
href: framework/wpf/index.md?view=netframeworkdesktop-4.8&preserve-view=true
- name: XAML language reference
href: xaml-services/?view=&preserve-view=true
+12 -3
View File
@@ -135,23 +135,32 @@
"ms.author": "adegeo"
},
"fileMetadata": {
"breadcrumb_path": {
"xaml-services/**/**.md": "/dotnet/desktop/xaml-services/breadcrumb/toc.json"
},
"titleSuffix": {
"framework/winforms/**/**.md": "Windows Forms .NET Framework",
"net/winforms/**/**.md": "Windows Forms .NET",
"framework/wpf/**/**.md": "WPF .NET Framework",
"net/wpf/**/**.md": "WPF .NET"
"net/wpf/**/**.md": "WPF .NET",
"xaml-services/**/*.md": "XAML"
},
"ms.technology": {
"framework/winforms/**/**.md": "dotnet-winforms",
"framework/wpf/**/**.md": "dotnet-wpf",
"net/winforms/**/**.md": "dotnet-winforms",
"net/wpf/**/**.md": "dotnet-wpf"
"net/wpf/**/**.md": "dotnet-wpf",
"xaml-services/**/*.md": "dotnet-wpf"
},
"ms.prod": {
"framework/winforms/**/**.md": "dotnet-framework",
"framework/wpf/**/**.md": "dotnet-framework",
"net/winforms/**/**.md": "dotnet-desktop",
"net/wpf/**/**.md": "dotnet-desktop"
"net/wpf/**/**.md": "dotnet-desktop",
"xaml-services/**/*.md": "dotnet-desktop"
},
"ms.topic": {
"xaml-services/**/*.md": "reference"
}
},
"template": [],
@@ -1,15 +1,15 @@
items:
- name: Docs
tocHref: /?view=&preserve-view=true
topicHref: /?view=&preserve-view=true
tocHref: /
topicHref: /
items:
- name: .NET
tocHref: /dotnet/?view=&preserve-view=true
topicHref: /dotnet/index?view=&preserve-view=true
tocHref: /dotnet/
topicHref: /dotnet/index
items:
- name: Desktop Guide
tocHref: /dotnet/desktop?view=&preserve-view=true
topicHref: /dotnet/desktop/index?view=&preserve-view=true
tocHref: /dotnet/desktop
topicHref: /dotnet/desktop/index
items:
- name: .NET Framework
items:
+19 -6
View File
@@ -1,18 +1,31 @@
items:
- name: Docs
tocHref: /?view=&preserve-view=true
topicHref: /?view=&preserve-view=true
tocHref: /
topicHref: /
items:
- name: .NET
tocHref: /dotnet/?view=&preserve-view=true
topicHref: /dotnet/index?view=&preserve-view=true
tocHref: /dotnet/
topicHref: /dotnet/index
items:
- name: Desktop Guide
tocHref: /dotnet/desktop?view=&preserve-view=true
topicHref: /dotnet/desktop/index?view=&preserve-view=true
tocHref: /dotnet/desktop
topicHref: /dotnet/desktop/index
items:
- name: ".NET 5 (and .NET Core 3.1)"
items:
- name: Windows Forms
tocHref: /dotnet/desktop/winforms/
topicHref: /dotnet/desktop/winforms/index
- name: Windows Presentation Foundation
tocHref: /dotnet/desktop/wpf/
topicHref: /dotnet/desktop/wpf/index
items:
- name: Get started
tocHref: /visualstudio/get-started/csharp/tutorial-wpf
topicHref: /dotnet/desktop/wpf/getting-started/index
- name: Migration
tocHref: /dotnet/desktop/wpf/migration
topicHref: /dotnet/desktop/wpf/migration/index
- name: Data binding
tocHref: /dotnet/desktop/wpf/data
topicHref: /dotnet/desktop/wpf/data/index
@@ -1,3 +1,3 @@
> [!IMPORTANT]
> The Desktop Guide documentation for .NET 5 (and .NET Core) and later versions is under construction and hasn't been published yet.
> The Desktop Guide documentation for .NET 5 (and .NET Core) and is under construction.
@@ -0,0 +1,445 @@
---
title: Data binding overview
description: Learn about the different data sources you can add to your project in Windows Presentation Foundation for .NET Core. Data sources can be bound to XAML elements to create dynamic apps.
author: adegeo
ms.date: 09/19/2019
ms.author: adegeo
dev_langs:
- "csharp"
- "vb"
---
# Data binding overview in WPF
Data binding in Windows Presentation Foundation (WPF) provides a simple and consistent way for apps to present and interact with data. Elements can be bound to data from a variety of data sources in the form of .NET objects and XML. Any <xref:System.Windows.Controls.ContentControl> such as <xref:System.Windows.Controls.Button> and any <xref:System.Windows.Controls.ItemsControl>, such as <xref:System.Windows.Controls.ListBox> and <xref:System.Windows.Controls.ListView>, have built-in functionality to enable flexible styling of single data items or collections of data items. Sort, filter, and group views can be generated on top of the data.
The data binding functionality in WPF has several advantages over traditional models, including inherent support for data binding by a broad range of properties, flexible UI representation of data, and clean separation of business logic from UI.
This article first discusses concepts fundamental to WPF data binding and then covers the usage of the <xref:System.Windows.Data.Binding> class and other features of data binding.
[!INCLUDE [desktop guide under construction](../../includes/desktop-guide-preview-note.md)]
## What is data binding?
Data binding is the process that establishes a connection between the app UI and the data it displays. If the binding has the correct settings and the data provides the proper notifications, when the data changes its value, the elements that are bound to the data reflect changes automatically. Data binding can also mean that if an outer representation of the data in an element changes, then the underlying data can be automatically updated to reflect the change. For example, if the user edits the value in a `TextBox` element, the underlying data value is automatically updated to reflect that change.
A typical use of data binding is to place server or local configuration data into forms or other UI controls. In WPF, this concept is expanded to include binding a broad range of properties to a variety of data sources. In WPF, dependency properties of elements can be bound to .NET objects (including ADO.NET objects or objects associated with Web Services and Web properties) and XML data.
For an example of data binding, take a look at the following app UI from the [Data Binding Demo][data-binding-demo], which displays a list of auction items.
![Data binding sample screenshot](./media/data-binding-overview/demo.png "DataBinding_DataBindingDemo")
The app demonstrates the following features of data binding:
- The content of the ListBox is bound to a collection of *AuctionItem* objects. An *AuctionItem* object has properties such as *Description*, *StartPrice*, *StartDate*, *Category*, *SpecialFeatures*, and so on.
- The data (*AuctionItem* objects) displayed in the `ListBox` is templated so that the description and the current price are shown for each item. The template is created by using a <xref:System.Windows.DataTemplate>. In addition, the appearance of each item depends on the *SpecialFeatures* value of the *AuctionItem* being displayed. If the *SpecialFeatures* value of the *AuctionItem* is *Color*, the item has a blue border. If the value is *Highlight*, the item has an orange border and a star. The [Data Templating](#data-templating) section provides information about data templating.
- The user can group, filter, or sort the data using the `CheckBoxes` provided. In the image above, the **Group by category** and **Sort by category and date** `CheckBoxes` are selected. You may have noticed that the data is grouped based on the category of the product, and the category name is in alphabetical order. It is difficult to notice from the image but the items are also sorted by the start date within each category. Sorting is done using a *collection view*. The [Binding to collections](#binding-to-collections) section discusses collection views.
- When the user selects an item, the <xref:System.Windows.Controls.ContentControl> displays the details of the selected item. This experience is called the *Master-detail scenario*. The [Master-detail scenario](#master-detail-binding-scenario) section provides information about this type of binding.
- The type of the *StartDate* property is <xref:System.DateTime>, which returns a date that includes the time to the millisecond. In this app, a custom converter has been used so that a shorter date string is displayed. The [Data conversion](#data-conversion) section provides information about converters.
When the user selects the *Add Product* button, the following form comes up.
![Add Product Listing page](./media/data-binding-overview/demo-addproductlisting.png "DataBinding_Demo_AddProductListing")
The user can edit the fields in the form, preview the product listing using the short or detailed preview panes, and select `Submit` to add the new product listing. Any existing grouping, filtering and sorting settings will apply to the new entry. In this particular case, the item entered in the above image will be displayed as the second item within the *Computer* category.
Not shown in this image is the validation logic provided in the *Start Date* <xref:System.Windows.Controls.TextBox>. If the user enters an invalid date (invalid formatting or a past date), the user will be notified with a <xref:System.Windows.Controls.ToolTip> and a red exclamation point next to the <xref:System.Windows.Controls.TextBox>. The [Data Validation](#data-validation) section discusses how to create validation logic.
Before going into the different features of data binding outlined above, we will first discuss the fundamental concepts that are critical to understanding WPF data binding.
## Basic data binding concepts
Regardless of what element you are binding and the nature of your data source, each binding always follows the model illustrated by the following figure.
![Diagram that shows the basic data binding model.](./media/data-binding-overview/basic-data-binding-diagram.png)
As the figure shows, data binding is essentially the bridge between your binding target and your binding source. The figure demonstrates the following fundamental WPF data binding concepts:
- Typically, each binding has four components:
- A binding target object.
- A target property.
- A binding source.
- A path to the value in the binding source to use.
> For example, if you want to bind the content of a `TextBox` to the `Employee.Name` property, your target object is the `TextBox`, the target property is the <xref:System.Windows.Controls.TextBox.Text%2A> property, the value to use is *Name*, and the source object is the *Employee* object.
- The target property must be a dependency property. Most <xref:System.Windows.UIElement> properties are dependency properties, and most dependency properties, except read-only ones, support data binding by default. (Only types derived from <xref:System.Windows.DependencyObject> can define dependency properties; and all <xref:System.Windows.UIElement> types derive from `DependencyObject`.)
- Although not shown in the figure, it should be noted that the binding source object is not restricted to being a custom .NET object. WPF data binding supports data in the form of .NET objects and XML. To provide some examples, your binding source may be a <xref:System.Windows.UIElement>, any list object, an ADO.NET or Web Services object, or an XmlNode that contains your XML data. For more information, see [Binding sources overview](../../../framework/wpf/data/binding-sources-overview.md).
It is important to remember that when you are establishing a binding, you are binding a binding target *to* a binding source. For example, if you are displaying some underlying XML data in a <xref:System.Windows.Controls.ListBox> using data binding, you are binding your `ListBox` to the XML data.
To establish a binding, you use the <xref:System.Windows.Data.Binding> object. The rest of this article discusses many of the concepts associated with and some of the properties and usage of the `Binding` object.
### Direction of the data flow
As indicated by the arrow in the previous figure, the data flow of a binding can go from the binding target to the binding source (for example, the source value changes when a user edits the value of a `TextBox`) and/or from the binding source to the binding target (for example, your `TextBox` content is updated with changes in the binding source) if the binding source provides the proper notifications.
You may want your app to enable users to change the data and propagate it back to the source object. Or you may not want to enable users to update the source data. You can control the flow of data by setting the <xref:System.Windows.Data.Binding.Mode?displayProperty=nameWithType>.
This figure illustrates the different types of data flow:
![Data binding data flow](./media/data-binding-overview/databinding-dataflow.png "DataBinding_DataFlow")
- <xref:System.Windows.Data.BindingMode.OneWay> binding causes changes to the source property to automatically update the target property, but changes to the target property are not propagated back to the source property. This type of binding is appropriate if the control being bound is implicitly read-only. For instance, you may bind to a source such as a stock ticker, or perhaps your target property has no control interface provided for making changes, such as a data-bound background color of a table. If there is no need to monitor the changes of the target property, using the <xref:System.Windows.Data.BindingMode.OneWay> binding mode avoids the overhead of the <xref:System.Windows.Data.BindingMode.TwoWay> binding mode.
- <xref:System.Windows.Data.BindingMode.TwoWay> binding causes changes to either the source property or the target property to automatically update the other. This type of binding is appropriate for editable forms or other fully interactive UI scenarios. Most properties default to <xref:System.Windows.Data.BindingMode.OneWay> binding, but some dependency properties (typically properties of user-editable controls such as the <xref:System.Windows.Controls.TextBox.Text?displayProperty=nameWithType> and [CheckBox.IsChecked](xref:System.Windows.Controls.Primitives.ToggleButton.IsChecked) default to <xref:System.Windows.Data.BindingMode.TwoWay> binding. A programmatic way to determine whether a dependency property binds one-way or two-way by default is to get the property metadata with <xref:System.Windows.DependencyProperty.GetMetadata%2A?displayProperty=nameWithType> and then check the Boolean value of the <xref:System.Windows.FrameworkPropertyMetadata.BindsTwoWayByDefault%2A?displayProperty=nameWithType> property.
- <xref:System.Windows.Data.BindingMode.OneWayToSource> is the reverse of <xref:System.Windows.Data.BindingMode.OneWay> binding; it updates the source property when the target property changes. One example scenario is if you only need to reevaluate the source value from the UI.
- Not illustrated in the figure is <xref:System.Windows.Data.BindingMode.OneTime> binding, which causes the source property to initialize the target property but does not propagate subsequent changes. If the data context changes or the object in the data context changes, the change is *not* reflected in the target property. This type of binding is appropriate if either a snapshot of the current state is appropriate or the data is truly static. This type of binding is also useful if you want to initialize your target property with some value from a source property and the data context is not known in advance. This mode is essentially a simpler form of <xref:System.Windows.Data.BindingMode.OneWay> binding that provides better performance in cases where the source value does not change.
To detect source changes (applicable to <xref:System.Windows.Data.BindingMode.OneWay> and <xref:System.Windows.Data.BindingMode.TwoWay> bindings), the source must implement a suitable property change notification mechanism such as <xref:System.ComponentModel.INotifyPropertyChanged>. See [How to: Implement property change notification](../../../framework/wpf/data/how-to-implement-property-change-notification.md) for an example of an <xref:System.ComponentModel.INotifyPropertyChanged> implementation.
The <xref:System.Windows.Data.Binding.Mode?displayProperty=nameWithType> property provides more information about binding modes and an example of how to specify the direction of a binding.
### What triggers source updates
Bindings that are <xref:System.Windows.Data.BindingMode.TwoWay> or <xref:System.Windows.Data.BindingMode.OneWayToSource> listen for changes in the target property and propagate them back to the source, known as updating the source. For example, you may edit the text of a TextBox to change the underlying source value.
However, is your source value updated while you are editing the text or after you finish editing the text and the control loses focus? The <xref:System.Windows.Data.Binding.UpdateSourceTrigger?displayProperty=nameWithType> property determines what triggers the update of the source. The dots of the right arrows in the following figure illustrate the role of the <xref:System.Windows.Data.Binding.UpdateSourceTrigger?displayProperty=nameWithType> property.
![Diagram that shows the role of the UpdateSourceTrigger property.](./media/data-binding-overview/data-binding-updatesource-trigger.png)
If the `UpdateSourceTrigger` value is <xref:System.Windows.Data.UpdateSourceTrigger.PropertyChanged?displayProperty=nameWithType>, then the value pointed to by the right arrow of <xref:System.Windows.Data.BindingMode.TwoWay> or the <xref:System.Windows.Data.BindingMode.OneWayToSource> bindings is updated as soon as the target property changes. However, if the `UpdateSourceTrigger` value is <xref:System.Windows.Data.UpdateSourceTrigger.LostFocus>, then that value only is updated with the new value when the target property loses focus.
Similar to the <xref:System.Windows.Data.Binding.Mode%2A> property, different dependency properties have different default <xref:System.Windows.Data.Binding.UpdateSourceTrigger%2A> values. The default value for most dependency properties is <xref:System.Windows.Data.UpdateSourceTrigger.PropertyChanged>, while the `TextBox.Text` property has a default value of <xref:System.Windows.Data.UpdateSourceTrigger.LostFocus>. `PropertyChanged` means the source updates usually happen whenever the target property changes. Instant changes are fine for CheckBoxes and other simple controls. However, for text fields, updating after every keystroke can diminish performance and denies the user the usual opportunity to backspace and fix typing errors before committing to the new value.
See the <xref:System.Windows.Data.Binding.UpdateSourceTrigger%2A> property page for information about how to find the default value of a dependency property.
The following table provides an example scenario for each <xref:System.Windows.Data.Binding.UpdateSourceTrigger%2A> value using the <xref:System.Windows.Controls.TextBox> as an example.
| UpdateSourceTrigger value | When the source value is updated | Example scenario for TextBox |
| ------------------------- | ---------------------------------- | ---------------------------- |
| `LostFocus` (default for <xref:System.Windows.Controls.TextBox.Text%2A?displayProperty=nameWithType>) | When the TextBox control loses focus. | A TextBox that is associated with validation logic (see [Data Validation](#data-validation) below). |
| `PropertyChanged` | As you type into the <xref:System.Windows.Controls.TextBox>. | TextBox controls in a chat room window. |
| `Explicit` | When the app calls <xref:System.Windows.Data.BindingExpression.UpdateSource%2A>. | TextBox controls in an editable form (updates the source values only when the user clicks the submit button). |
For an example, see [How to: Control when the TextBox text updates the source](../../../framework/wpf/data/how-to-control-when-the-textbox-text-updates-the-source.md).
## Creating a binding
To restate some of the concepts discussed in the previous sections, you establish a binding using the <xref:System.Windows.Data.Binding> object, and each binding usually has four components: a binding target, a target property, a binding source, and a path to the source value to use. This section discusses how to set up a binding.
Consider the following example, in which the binding source object is a class named *MyData* that is defined in the *SDKSample* namespace. For demonstration purposes, *MyData* has a string property named *ColorName* whose value is set to "Red". Thus, this example generates a button with a red background.
[!code-xaml[BindNonTextProperty](./snippets/data-binding-overview/csharp/AutoConvertPropertyToColor.xaml#BindAutoConvertColor)]
For more information on the binding declaration syntax and examples of how to set up a binding in code, see [Binding Declarations Overview](../../../framework/wpf/data/binding-declarations-overview.md).
If we apply this example to our basic diagram, the resulting figure looks like the following. This figure describes a <xref:System.Windows.Data.BindingMode.OneWay> binding because the Background property supports <xref:System.Windows.Data.BindingMode.OneWay> binding by default.
![Diagram that shows the data binding Background property.](./media/data-binding-overview/data-binding-button-background-example.png)
You may wonder why this binding works even though the *ColorName* property is of type string while the <xref:System.Windows.Controls.Control.Background%2A> property is of type <xref:System.Windows.Media.Brush>. This binding uses default type conversion, which is discussed in the [Data conversion](#data-conversion) section.
### Specifying the binding source
Notice that in the previous example, the binding source is specified by setting the [DockPanel.DataContext](xref:System.Windows.FrameworkElement.DataContext) property. The <xref:System.Windows.Controls.Button> then inherits the <xref:System.Windows.FrameworkElement.DataContext%2A> value from the <xref:System.Windows.Controls.DockPanel>, which is its parent element. To reiterate, the binding source object is one of the four necessary components of a binding. Therefore, without the binding source object being specified, the binding would do nothing.
There are several ways to specify the binding source object. Using the <xref:System.Windows.FrameworkElement.DataContext%2A> property on a parent element is useful when you are binding multiple properties to the same source. However, sometimes it may be more appropriate to specify the binding source on individual binding declarations. For the previous example, instead of using the <xref:System.Windows.FrameworkElement.DataContext%2A> property, you can specify the binding source by setting the <xref:System.Windows.Data.Binding.Source%2A?displayProperty=nameWithType> property directly on the binding declaration of the button, as in the following example.
[!code-xaml[BindNonTextPropertyCompactBinding](./snippets/data-binding-overview/csharp/AutoConvertPropertyToColor.xaml#BindAutoConvertColorCompactBinding)]
Other than setting the <xref:System.Windows.FrameworkElement.DataContext%2A> property on an element directly, inheriting the <xref:System.Windows.FrameworkElement.DataContext%2A> value from an ancestor (such as the button in the first example), and explicitly specifying the binding source by setting the <xref:System.Windows.Data.Binding.Source%2A?displayProperty=nameWithType> property on the binding (such as the button the last example), you can also use the <xref:System.Windows.Data.Binding.ElementName?displayProperty=nameWithType> property or the <xref:System.Windows.Data.Binding.RelativeSource?displayProperty=nameWithType> property to specify the binding source. The <xref:System.Windows.Data.Binding.ElementName%2A> property is useful when you are binding to other elements in your app, such as when you are using a slider to adjust the width of a button. The <xref:System.Windows.Data.Binding.RelativeSource%2A> property is useful when the binding is specified in a <xref:System.Windows.Controls.ControlTemplate> or a <xref:System.Windows.Style>. For more information, see [How to: Specify the binding source](../../../framework/wpf/data/how-to-specify-the-binding-source.md).
### Specifying the path to the value
If your binding source is an object, you use the <xref:System.Windows.Data.Binding.Path?displayProperty=nameWithType> property to specify the value to use for your binding. If you are binding to XML data, you use the <xref:System.Windows.Data.Binding.XPath?displayProperty=nameWithType> property to specify the value. In some cases, it may be applicable to use the <xref:System.Windows.Data.Binding.Path%2A> property even when your data is XML. For example, if you want to access the Name property of a returned XmlNode (as a result of an XPath query), you should use the <xref:System.Windows.Data.Binding.Path%2A> property in addition to the <xref:System.Windows.Data.Binding.XPath%2A> property.
For more information, see the <xref:System.Windows.Data.Binding.Path%2A> and <xref:System.Windows.Data.Binding.XPath%2A> properties.
Although we have emphasized that the <xref:System.Windows.Data.Binding.Path%2A> to the value to use is one of the four necessary components of a binding, in the scenarios that you want to bind to an entire object, the value to use would be the same as the binding source object. In those cases, it is applicable to not specify a <xref:System.Windows.Data.Binding.Path%2A>. Consider the following example.
[!code-xaml[EmptyBinding](./snippets/data-binding-overview/csharp/EmptyBinding.xaml#EmptyBinding)]
The above example uses the empty binding syntax: {Binding}. In this case, the <xref:System.Windows.Controls.ListBox> inherits the DataContext from a parent DockPanel element (not shown in this example). When the path is not specified, the default is to bind to the entire object. In other words, in this example, the path has been left out because we are binding the <xref:System.Windows.Controls.ItemsControl.ItemsSource%2A> property to the entire object. (See the [Binding to collections](#binding-to-collections) section for an in-depth discussion.)
Other than binding to a collection, this scenario is also useful when you want to bind to an entire object instead of just a single property of an object. For example, if your source object is of type <xref:System.String>, you may simply want to bind to the string itself. Another common scenario is when you want to bind an element to an object with several properties.
You may need to apply custom logic so that the data is meaningful to your bound target property. The custom logic may be in the form of a custom converter if default type conversion does not exist. See [Data conversion](#data-conversion) for information about converters.
### Binding and BindingExpression
Before getting into other features and usages of data binding, it is useful to introduce the <xref:System.Windows.Data.BindingExpression> class. As you have seen in previous sections, the <xref:System.Windows.Data.Binding> class is the high-level class for the declaration of a binding; it provides many properties that allow you to specify the characteristics of a binding. A related class, <xref:System.Windows.Data.BindingExpression>, is the underlying object that maintains the connection between the source and the target. A binding contains all the information that can be shared across several binding expressions. A <xref:System.Windows.Data.BindingExpression> is an instance expression that cannot be shared and contains all the instance information of the <xref:System.Windows.Data.Binding>.
Consider the following example, where `myDataObject` is an instance of the `MyData` class, `myBinding` is the source <xref:System.Windows.Data.Binding> object, and `MyData` is a defined class that contains a string property named `ColorName`. This example binds the text content of `myText`, an instance of <xref:System.Windows.Controls.TextBlock>, to `ColorName`.
[!code-csharp[CodeOnlyBinding](./snippets/data-binding-overview/csharp/ManualBinding.cs#CodeOnlyBinding)]
[!code-vb[CodeOnlyBinding](./snippets/data-binding-overview/vb/ManualBinding.vb#CodeOnlyBinding)]
You can use the same *myBinding* object to create other bindings. For example, you can use the *myBinding* object to bind the text content of a check box to *ColorName*. In that scenario, there will be two instances of <xref:System.Windows.Data.BindingExpression> sharing the *myBinding* object.
A <xref:System.Windows.Data.BindingExpression> object is returned by calling <xref:System.Windows.Data.BindingOperations.GetBindingExpression%2A> on a data-bound object. The following articles demonstrate some of the usages of the <xref:System.Windows.Data.BindingExpression> class:
- [Get the binding object from a bound target property](../../../framework/wpf/data/how-to-get-the-binding-object-from-a-bound-target-property.md)
- [Control When the TextBox text updates the source](../../../framework/wpf/data/how-to-control-when-the-textbox-text-updates-the-source.md)
## Data conversion
In the [Creating a binding](#creating-a-binding) section, the button is red because its <xref:System.Windows.Controls.Control.Background%2A> property is bound to a string property with the value "Red". This string value works because a type converter is present on the <xref:System.Windows.Media.Brush> type to convert the string value to a <xref:System.Windows.Media.Brush>.
Adding this information to the figure in the [Creating a Binding](#creating-a-binding) section looks like this.
![Diagram that shows the data binding Default property.](./media/data-binding-overview/data-binding-button-default-conversion.png)
However, what if instead of having a property of type string your binding source object has a *Color* property of type <xref:System.Windows.Media.Color>? In that case, in order for the binding to work you would need to first turn the *Color* property value into something that the <xref:System.Windows.Controls.Control.Background%2A> property accepts. You would need to create a custom converter by implementing the <xref:System.Windows.Data.IValueConverter> interface, as in the following example.
[!code-csharp[CodeOnlyBinding](./snippets/data-binding-overview/csharp/ColorBrushConverter.cs#ColorBrushConverter)]
[!code-vb[CodeOnlyBinding](./snippets/data-binding-overview/vb/ColorBrushConverter.vb#ColorBrushConverter)]
See <xref:System.Windows.Data.IValueConverter> for more information.
Now the custom converter is used instead of default conversion, and our diagram looks like this.
![Diagram that shows the data binding custom converter.](./media/data-binding-overview/data-binding-converter-color-example.png)
To reiterate, default conversions may be available because of type converters that are present in the type being bound to. This behavior will depend on which type converters are available in the target. If in doubt, create your own converter.
The following are some typical scenarios where it makes sense to implement a data converter:
- Your data should be displayed differently, depending on culture. For instance, you might want to implement a currency converter or a calendar date/time converter based on the conventions used in a particular culture.
- The data being used is not necessarily intended to change the text value of a property, but is instead intended to change some other value, such as the source for an image, or the color or style of the display text. Converters can be used in this instance by converting the binding of a property that might not seem to be appropriate, such as binding a text field to the Background property of a table cell.
- More than one control or multiple properties of controls are bound to the same data. In this case, the primary binding might just display the text, whereas other bindings handle specific display issues but still use the same binding as source information.
- A target property has a collection of bindings, which is termed <xref:System.Windows.Data.MultiBinding>. For <xref:System.Windows.Data.MultiBinding>, you use a custom <xref:System.Windows.Data.IMultiValueConverter> to produce a final value from the values of the bindings. For example, color may be computed from red, blue, and green values, which can be values from the same or different binding source objects. See <xref:System.Windows.Data.MultiBinding> for examples and information.
## Binding to collections
A binding source object can be treated either as a single object whose properties contain data or as a data collection of polymorphic objects that are often grouped together (such as the result of a query to a database). So far we've only discussed binding to single objects. However, binding to a data collection is a common scenario. For example, a common scenario is to use an <xref:System.Windows.Controls.ItemsControl> such as a <xref:System.Windows.Controls.ListBox>, <xref:System.Windows.Controls.ListView>, or <xref:System.Windows.Controls.TreeView> to display a data collection, such as in the app shown in the [What is data binding](#what-is-data-binding) section.
Fortunately, our basic diagram still applies. If you are binding an <xref:System.Windows.Controls.ItemsControl> to a collection, the diagram looks like this.
![Diagram that shows the data binding ItemsControl object.](./media/data-binding-overview/data-binding-itemscontrol.png)
As shown in this diagram, to bind an <xref:System.Windows.Controls.ItemsControl> to a collection object, <xref:System.Windows.Controls.ItemsControl.ItemsSource%2A?displayProperty=nameWithType> property is the property to use. You can think of `ItemsSource` as the content of the <xref:System.Windows.Controls.ItemsControl>. The binding is <xref:System.Windows.Data.BindingMode.OneWay> because the `ItemsSource` property supports `OneWay` binding by default.
### How to implement collections
You can enumerate over any collection that implements the <xref:System.Collections.IEnumerable> interface. However, to set up dynamic bindings so that insertions or deletions in the collection update the UI automatically, the collection must implement the <xref:System.Collections.Specialized.INotifyCollectionChanged> interface. This interface exposes an event that should be raised whenever the underlying collection changes.
WPF provides the <xref:System.Collections.ObjectModel.ObservableCollection%601> class, which is a built-in implementation of a data collection that exposes the <xref:System.Collections.Specialized.INotifyCollectionChanged> interface. To fully support transferring data values from source objects to targets, each object in your collection that supports bindable properties must also implement the <xref:System.ComponentModel.INotifyPropertyChanged> interface. For more information, see [Binding sources overview](../../../framework/wpf/data/binding-sources-overview.md).
Before implementing your own collection, consider using <xref:System.Collections.ObjectModel.ObservableCollection%601> or one of the existing collection classes, such as <xref:System.Collections.Generic.List%601>, <xref:System.Collections.ObjectModel.Collection%601>, and <xref:System.ComponentModel.BindingList%601>, among many others. If you have an advanced scenario and want to implement your own collection, consider using <xref:System.Collections.IList>, which provides a non-generic collection of objects that can be individually accessed by the index, and thus provides the best performance.
### Collection views
Once your <xref:System.Windows.Controls.ItemsControl> is bound to a data collection, you may want to sort, filter, or group the data. To do that, you use collection views, which are classes that implement the <xref:System.ComponentModel.ICollectionView> interface.
#### What Are collection views?
A collection view is a layer on top of a binding source collection that allows you to navigate and display the source collection based on sort, filter, and group queries, without having to change the underlying source collection itself. A collection view also maintains a pointer to the current item in the collection. If the source collection implements the <xref:System.Collections.Specialized.INotifyCollectionChanged> interface, the changes raised by the <xref:System.Collections.Specialized.INotifyCollectionChanged.CollectionChanged> event are propagated to the views.
Because views do not change the underlying source collections, each source collection can have multiple views associated with it. For example, you may have a collection of *Task* objects. With the use of views, you can display that same data in different ways. For example, on the left side of your page you may want to show tasks sorted by priority, and on the right side, grouped by area.
#### How to create a view
One way to create and use a view is to instantiate the view object directly and then use it as the binding source. For example, consider the [Data binding demo][data-binding-demo] app shown in the [What is data binding](#what-is-data-binding) section. The app is implemented such that the <xref:System.Windows.Controls.ListBox> binds to a view over the data collection instead of the data collection directly. The following example is extracted from the [Data binding demo][data-binding-demo] app. The <xref:System.Windows.Data.CollectionViewSource> class is the XAML proxy of a class that inherits from <xref:System.Windows.Data.CollectionView>. In this particular example, the <xref:System.Windows.Data.CollectionViewSource.Source%2A> of the view is bound to the *AuctionItems* collection (of type <xref:System.Collections.ObjectModel.ObservableCollection%601>) of the current app object.
[!code-xaml[CollectionView](./snippets/data-binding-overview/csharp/CollectionView.xaml#CollectionView)]
The resource *listingDataView* then serves as the binding source for elements in the app, such as the <xref:System.Windows.Controls.ListBox>.
[!code-xaml[ListBoxCollectionView](./snippets/data-binding-overview/csharp/CollectionView.xaml#ListBoxCollectionView)]
To create another view for the same collection, you can create another <xref:System.Windows.Data.CollectionViewSource> instance and give it a different `x:Key` name.
The following table shows what view data types are created as the default collection view or by <xref:System.Windows.Data.CollectionViewSource> based on the source collection type.
| Source collection type | Collection view type | Notes |
| ----------------------------------------- | -------------------- | ----- |
| <xref:System.Collections.IEnumerable> | An internal type based on <xref:System.Windows.Data.CollectionView> | Cannot group items. |
| <xref:System.Collections.IList> | <xref:System.Windows.Data.ListCollectionView> | Fastest. |
| <xref:System.ComponentModel.IBindingList> | <xref:System.Windows.Data.BindingListCollectionView> | |
#### Using a default view
Specifying a collection view as a binding source is one way to create and use a collection view. WPF also creates a default collection view for every collection used as a binding source. If you bind directly to a collection, WPF binds to its default view. This default view is shared by all bindings to the same collection, so a change made to a default view by one bound control or code (such as sorting or a change to the current item pointer, discussed later) is reflected in all other bindings to the same collection.
To get the default view, you use the <xref:System.Windows.Data.CollectionViewSource.GetDefaultView%2A> method. For an example, see [Get the default view of a data collection](../../../framework/wpf/data/how-to-get-the-default-view-of-a-data-collection.md).
#### Collection views with ADO.NET DataTables
To improve performance, collection views for ADO.NET <xref:System.Data.DataTable> or <xref:System.Data.DataView> objects delegate sorting and filtering to the <xref:System.Data.DataView>, which causes sorting and filtering to be shared across all collection views of the data source. To enable each collection view to sort and filter independently, initialize each collection view with its own <xref:System.Data.DataView> object.
#### Sorting
As mentioned before, views can apply a sort order to a collection. As it exists in the underlying collection, your data may or may not have a relevant, inherent order. The view over the collection allows you to impose an order, or change the default order, based on comparison criteria that you supply. Because it is a client-based view of the data, a common scenario is that the user might want to sort columns of tabular data per the value that the column corresponds to. Using views, this user-driven sort can be applied, again without making any changes to the underlying collection or even having to requery for the collection content. For an example, see [Sort a GridView column when a header is clicked](../../../framework/wpf/controls/how-to-sort-a-gridview-column-when-a-header-is-clicked.md).
The following example shows the sorting logic of the "Sort by category and date" <xref:System.Windows.Controls.CheckBox> of the app UI in the [What is data binding](#what-is-data-binding) section.
[!code-csharp[AddSortChecked](./snippets/data-binding-overview/csharp/CollectionView.xaml.cs#AddSortChecked)]
[!code-vb[AddSortChecked](./snippets/data-binding-overview/vb/CollectionView.xaml.vb#AddSortChecked)]
#### Filtering
Views can also apply a filter to a collection, so that the view shows only a certain subset of the full collection. You might filter on a condition in the data. For instance, as is done by the app in the [What is data binding](#what-is-data-binding) section, the "Show only bargains" <xref:System.Windows.Controls.CheckBox> contains logic to filter out items that cost $25 or more. The following code is executed to set *ShowOnlyBargainsFilter* as the <xref:System.Windows.Data.CollectionViewSource.Filter> event handler when that <xref:System.Windows.Controls.CheckBox> is selected.
[!code-csharp[ListingViewFilter](./snippets/data-binding-overview/csharp/CollectionView.xaml.cs#ListingViewFilter)]
[!code-vb[ListingViewFilter](./snippets/data-binding-overview/vb/CollectionView.xaml.vb#ListingViewFilter)]
The *ShowOnlyBargainsFilter* event handler has the following implementation.
[!code-csharp[FilterEvent](./snippets/data-binding-overview/csharp/CollectionView.xaml.cs#FilterEvent)]
[!code-vb[FilterEvent](./snippets/data-binding-overview/vb/CollectionView.xaml.vb#FilterEvent)]
If you are using one of the <xref:System.Windows.Data.CollectionView> classes directly instead of <xref:System.Windows.Data.CollectionViewSource>, you would use the <xref:System.Windows.Data.CollectionView.Filter%2A> property to specify a callback. For an example, see [Filter Data in a View](../../../framework/wpf/data/how-to-filter-data-in-a-view.md).
#### Grouping
Except for the internal class that views an <xref:System.Collections.IEnumerable> collection, all collection views support *grouping*, which allows the user to partition the collection in the collection view into logical groups. The groups can be explicit, where the user supplies a list of groups, or implicit, where the groups are generated dynamically depending on the data.
The following example shows the logic of the "Group by category" <xref:System.Windows.Controls.CheckBox>.
[!code-csharp[ListingGroupCheck](./snippets/data-binding-overview/csharp/CollectionView.xaml.cs#ListingGroupCheck)]
[!code-vb[ListingGroupCheck](./snippets/data-binding-overview/vb/CollectionView.xaml.vb#ListingGroupCheck)]
For another grouping example, see [Group Items in a ListView That Implements a GridView](../../../framework/wpf/controls/how-to-group-items-in-a-listview-that-implements-a-gridview.md).
#### Current item pointers
Views also support the notion of a current item. You can navigate through the objects in a collection view. As you navigate, you are moving an item pointer that allows you to retrieve the object that exists at that particular location in the collection. For an example, see [Navigate through the objects in a data CollectionView](../../../framework/wpf/data/how-to-navigate-through-the-objects-in-a-data-collectionview.md).
Because WPF binds to a collection only by using a view (either a view you specify, or the collection's default view), all bindings to collections have a current item pointer. When binding to a view, the slash ("/") character in a `Path` value designates the current item of the view. In the following example, the data context is a collection view. The first line binds to the collection. The second line binds to the current item in the collection. The third line binds to the `Description` property of the current item in the collection.
```xaml
<Button Content="{Binding }" />
<Button Content="{Binding Path=/}" />
<Button Content="{Binding Path=/Description}" />
```
The slash and property syntax can also be stacked to traverse a hierarchy of collections. The following example binds to the current item of a collection named `Offices`, which is a property of the current item of the source collection.
```xaml
<Button Content="{Binding /Offices/}" />
```
The current item pointer can be affected by any sorting or filtering that is applied to the collection. Sorting preserves the current item pointer on the last item selected, but the collection view is now restructured around it. (Perhaps the selected item was at the beginning of the list before, but now the selected item might be somewhere in the middle.) Filtering preserves the selected item if that selection remains in view after the filtering. Otherwise, the current item pointer is set to the first item of the filtered collection view.
#### Master-detail binding scenario
The notion of a current item is useful not only for navigation of items in a collection, but also for the master-detail binding scenario. Consider the app UI in the [What is data binding](#what-is-data-binding) section again. In that app, the selection within the <xref:System.Windows.Controls.ListBox> determines the content shown in the <xref:System.Windows.Controls.ContentControl>. To put it in another way, when a <xref:System.Windows.Controls.ListBox> item is selected, the <xref:System.Windows.Controls.ContentControl> shows the details of the selected item.
You can implement the master-detail scenario simply by having two or more controls bound to the same view. The following example from the [Data binding demo][data-binding-demo] shows the markup of the <xref:System.Windows.Controls.ListBox> and the <xref:System.Windows.Controls.ContentControl> you see on the app UI in the [What is data binding](#what-is-data-binding) section.
[!code-xaml[ListBoxContentControl](./snippets/data-binding-overview/csharp/CollectionView.xaml#ListBoxContentControl)]
Notice that both of the controls are bound to the same source, the *listingDataView* static resource (see the definition of this resource in the [How to create a view section](#how-to-create-a-view)). This binding works because when a singleton object (the <xref:System.Windows.Controls.ContentControl> in this case) is bound to a collection view, it automatically binds to the <xref:System.Windows.Data.CollectionView.CurrentItem%2A> of the view. The <xref:System.Windows.Data.CollectionViewSource> objects automatically synchronize currency and selection. If your list control is not bound to a <xref:System.Windows.Data.CollectionViewSource> object as in this example, then you would need to set its <xref:System.Windows.Controls.Primitives.Selector.IsSynchronizedWithCurrentItem%2A> property to `true` for this to work.
For other examples, see [Bind to a collection and display information based on selection](../../../framework/wpf/data/how-to-bind-to-a-collection-and-display-information-based-on-selection.md) and [Use the master-detail pattern with hierarchical data](../../../framework/wpf/data/how-to-use-the-master-detail-pattern-with-hierarchical-data.md).
You may have noticed that the above example uses a template. In fact, the data would not be displayed the way we wish without the use of templates (the one explicitly used by the <xref:System.Windows.Controls.ContentControl> and the one implicitly used by the <xref:System.Windows.Controls.ListBox>). We now turn to data templating in the next section.
## Data templating
Without the use of data templates, our app UI in the [What is data binding](#what-is-data-binding) section would look like the following.
![Data Binding Demo without Data Templates](./media/data-binding-overview/demo-no-template.png)
As shown in the example in the previous section, both the <xref:System.Windows.Controls.ListBox> control and the <xref:System.Windows.Controls.ContentControl> are bound to the entire collection object (or more specifically, the view over the collection object) of *AuctionItem*s. Without specific instructions of how to display the data collection, the <xref:System.Windows.Controls.ListBox> displays the string representation of each object in the underlying collection, and the <xref:System.Windows.Controls.ContentControl> displays the string representation of the object it is bound to.
To solve that problem, the app defines <xref:System.Windows.DataTemplate?text=DataTemplates>. As shown in the example in the previous section, the <xref:System.Windows.Controls.ContentControl> explicitly uses the *detailsProductListingTemplate* data template. The <xref:System.Windows.Controls.ListBox> control implicitly uses the following data template when displaying the *AuctionItem* objects in the collection.
[!code-xaml[AuctionItemDataTemplate](./snippets/data-binding-overview/csharp/CollectionView.xaml#AuctionItemDataTemplate)]
With the use of those two DataTemplates, the resulting UI is the one shown in the [What is data binding](#what-is-data-binding) section. As you can see from that screenshot, in addition to letting you place data in your controls, DataTemplates allow you to define compelling visuals for your data. For example, <xref:System.Windows.DataTrigger>s are used in the above <xref:System.Windows.DataTemplate> so that *AuctionItem*s with *SpecialFeatures* value of *HighLight* would be displayed with an orange border and a star.
For more information about data templates, see the [Data templating overview](../../../framework/wpf/data/data-templating-overview.md).
## Data validation
Most app that take user input need to have validation logic to ensure that the user has entered the expected information. The validation checks can be based on type, range, format, or other app-specific requirements. This section discusses how data validation works in WPF.
### Associating validation rules with a binding
The WPF data binding model allows you to associate <xref:System.Windows.Data.Binding.ValidationRules%2A> with your <xref:System.Windows.Data.Binding> object. For example, the following example binds a <xref:System.Windows.Controls.TextBox> to a property named `StartPrice` and adds a <xref:System.Windows.Controls.ExceptionValidationRule> object to the <xref:System.Windows.Data.Binding.ValidationRules%2A?displayProperty=nameWithType> property.
[!code-xaml[TextboxStartPrice](./snippets/data-binding-overview/csharp/DataValidation.xaml#TextboxStartPrice)]
A <xref:System.Windows.Controls.ValidationRule> object checks whether the value of a property is valid. WPF has two types of built-in <xref:System.Windows.Controls.ValidationRule> objects:
- A <xref:System.Windows.Controls.ExceptionValidationRule> checks for exceptions thrown during the update of the binding source property. In the previous example, `StartPrice` is of type integer. When the user enters a value that cannot be converted to an integer, an exception is thrown, causing the binding to be marked as invalid. An alternative syntax to setting the <xref:System.Windows.Controls.ExceptionValidationRule> explicitly is to set the <xref:System.Windows.Data.Binding.ValidatesOnExceptions%2A> property to `true` on your <xref:System.Windows.Data.Binding> or <xref:System.Windows.Data.MultiBinding> object.
- A <xref:System.Windows.Controls.DataErrorValidationRule> object checks for errors that are raised by objects that implement the <xref:System.ComponentModel.IDataErrorInfo> interface. For an example of using this validation rule, see <xref:System.Windows.Controls.DataErrorValidationRule>. An alternative syntax to setting the <xref:System.Windows.Controls.DataErrorValidationRule> explicitly is to set the <xref:System.Windows.Data.Binding.ValidatesOnDataErrors%2A> property to `true` on your <xref:System.Windows.Data.Binding> or <xref:System.Windows.Data.MultiBinding> object.
You can also create your own validation rule by deriving from the <xref:System.Windows.Controls.ValidationRule> class and implementing the <xref:System.Windows.Controls.ValidationRule.Validate%2A> method. The following example shows the rule used by the *Add Product Listing* "Start Date" <xref:System.Windows.Controls.TextBox> from the [What is data binding](#what-is-data-binding) section.
[!code-csharp[FutureDateRule](./snippets/data-binding-overview/csharp/FutureDateRule.cs#FutureDateRule)]
[!code-vb[FutureDateRule](./snippets/data-binding-overview/vb/FutureDateRule.vb#FutureDateRule)]
The *StartDateEntryForm* <xref:System.Windows.Controls.TextBox> uses this *FutureDateRule*, as shown in the following example.
[!code-xaml[TextboxStartDate](./snippets/data-binding-overview/csharp/DataValidation.xaml#TextboxStartDate)]
Because the <xref:System.Windows.Data.Binding.UpdateSourceTrigger%2A> value is <xref:System.Windows.Data.UpdateSourceTrigger.PropertyChanged>, the binding engine updates the source value on every keystroke, which means it also checks every rule in the <xref:System.Windows.Data.Binding.ValidationRules%2A> collection on every keystroke. We discuss this further in the Validation Process section.
### Providing visual feedback
If the user enters an invalid value, you may want to provide some feedback about the error on the app UI. One way to provide such feedback is to set the <xref:System.Windows.Controls.Validation.ErrorTemplate%2A?displayProperty=nameWithType> attached property to a custom <xref:System.Windows.Controls.ControlTemplate>. As shown in the previous subsection, the *StartDateEntryForm* <xref:System.Windows.Controls.TextBox> uses an <xref:System.Windows.Controls.Validation.ErrorTemplate%2A> called *validationTemplate*. The following example shows the definition of *validationTemplate*.
[!code-xaml[ControlTemplate](./snippets/data-binding-overview/csharp/DataValidation.xaml#ControlTemplate)]
The <xref:System.Windows.Controls.AdornedElementPlaceholder> element specifies where the control being adorned should be placed.
In addition, you may also use a <xref:System.Windows.Controls.ToolTip> to display the error message. Both the *StartDateEntryForm* and the *StartPriceEntryForm*<xref:System.Windows.Controls.TextBox>es use the style *textStyleTextBox*, which creates a <xref:System.Windows.Controls.ToolTip> that displays the error message. The following example shows the definition of *textStyleTextBox*. The attached property <xref:System.Windows.Controls.Validation.HasError%2A?displayProperty=nameWithType> is `true` when one or more of the bindings on the properties of the bound element are in error.
[!code-xaml[TextBoxStyle](./snippets/data-binding-overview/csharp/DataValidation.xaml#TextBoxStyle)]
With the custom <xref:System.Windows.Controls.Validation.ErrorTemplate%2A> and the <xref:System.Windows.Controls.ToolTip>, the *StartDateEntryForm* <xref:System.Windows.Controls.TextBox> looks like the following when there is a validation error.
![Data binding validation error](./media/data-binding-overview/demo-validation-date.png "DataBindingDemo_Validation")
If your <xref:System.Windows.Data.Binding> has associated validation rules but you do not specify an <xref:System.Windows.Controls.Validation.ErrorTemplate%2A> on the bound control, a default <xref:System.Windows.Controls.Validation.ErrorTemplate%2A> will be used to notify users when there is a validation error. The default <xref:System.Windows.Controls.Validation.ErrorTemplate%2A> is a control template that defines a red border in the adorner layer. With the default <xref:System.Windows.Controls.Validation.ErrorTemplate%2A> and the <xref:System.Windows.Controls.ToolTip>, the UI of the *StartPriceEntryForm* <xref:System.Windows.Controls.TextBox> looks like the following when there is a validation error.
![Data binding validation error](./media/data-binding-overview/demo-validation-price.png "DataBindingDemo_ValidationDefault")
For an example of how to provide logic to validate all controls in a dialog box, see the Custom Dialog Boxes section in the [Dialog boxes overview](../../../framework/wpf/app-development/dialog-boxes-overview.md).
### Validation process
Validation usually occurs when the value of a target is transferred to the binding source property. This transfer occurs on <xref:System.Windows.Data.BindingMode.TwoWay> and <xref:System.Windows.Data.BindingMode.OneWayToSource> bindings. To reiterate, what causes a source update depends on the value of the <xref:System.Windows.Data.Binding.UpdateSourceTrigger%2A> property, as described in the [What triggers source updates](#what-triggers-source-updates) section.
The following items describe the *validation* process. If a validation error or other type of error occurs at any time during this process, the process is halted:
1. The binding engine checks if there are any custom <xref:System.Windows.Controls.ValidationRule> objects defined whose <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> is set to <xref:System.Windows.Controls.ValidationStep.RawProposedValue> for that <xref:System.Windows.Data.Binding>, in which case it calls the <xref:System.Windows.Controls.ValidationRule.Validate%2A> method on each <xref:System.Windows.Controls.ValidationRule> until one of them runs into an error or until all of them pass.
2. The binding engine then calls the converter, if one exists.
3. If the converter succeeds, the binding engine checks if there are any custom <xref:System.Windows.Controls.ValidationRule> objects defined whose <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> is set to <xref:System.Windows.Controls.ValidationStep.ConvertedProposedValue> for that <xref:System.Windows.Data.Binding>, in which case it calls the <xref:System.Windows.Controls.ValidationRule.Validate%2A> method on each <xref:System.Windows.Controls.ValidationRule> that has <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> set to <xref:System.Windows.Controls.ValidationStep.ConvertedProposedValue> until one of them runs into an error or until all of them pass.
4. The binding engine sets the source property.
5. The binding engine checks if there are any custom <xref:System.Windows.Controls.ValidationRule> objects defined whose <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> is set to <xref:System.Windows.Controls.ValidationStep.UpdatedValue> for that <xref:System.Windows.Data.Binding>, in which case it calls the <xref:System.Windows.Controls.ValidationRule.Validate%2A> method on each <xref:System.Windows.Controls.ValidationRule> that has <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> set to <xref:System.Windows.Controls.ValidationStep.UpdatedValue> until one of them runs into an error or until all of them pass. If a <xref:System.Windows.Controls.DataErrorValidationRule> is associated with a binding and its <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> is set to the default, <xref:System.Windows.Controls.ValidationStep.UpdatedValue>, the <xref:System.Windows.Controls.DataErrorValidationRule> is checked at this point. At this point any binding that has the <xref:System.Windows.Data.Binding.ValidatesOnDataErrors%2A> set to `true` is checked.
6. The binding engine checks if there are any custom <xref:System.Windows.Controls.ValidationRule> objects defined whose <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> is set to <xref:System.Windows.Controls.ValidationStep.CommittedValue> for that <xref:System.Windows.Data.Binding>, in which case it calls the <xref:System.Windows.Controls.ValidationRule.Validate%2A> method on each <xref:System.Windows.Controls.ValidationRule> that has <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> set to <xref:System.Windows.Controls.ValidationStep.CommittedValue> until one of them runs into an error or until all of them pass.
If a <xref:System.Windows.Controls.ValidationRule> does not pass at any time throughout this process, the binding engine creates a <xref:System.Windows.Controls.ValidationError> object and adds it to the <xref:System.Windows.Controls.Validation.Errors%2A?displayProperty=nameWithType> collection of the bound element. Before the binding engine runs the <xref:System.Windows.Controls.ValidationRule> objects at any given step, it removes any <xref:System.Windows.Controls.ValidationError> that was added to the <xref:System.Windows.Controls.Validation.Errors%2A?displayProperty=nameWithType> attached property of the bound element during that step. For example, if a <xref:System.Windows.Controls.ValidationRule> whose <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> is set to <xref:System.Windows.Controls.ValidationStep.UpdatedValue> failed, the next time the validation process occurs, the binding engine removes that <xref:System.Windows.Controls.ValidationError> immediately before it calls any <xref:System.Windows.Controls.ValidationRule> that has <xref:System.Windows.Controls.ValidationRule.ValidationStep%2A> set to <xref:System.Windows.Controls.ValidationStep.UpdatedValue>.
When <xref:System.Windows.Controls.Validation.Errors%2A?displayProperty=nameWithType> is not empty, the <xref:System.Windows.Controls.Validation.HasError%2A?displayProperty=nameWithType> attached property of the element is set to `true`. Also, if the <xref:System.Windows.Data.Binding.NotifyOnValidationError%2A> property of the <xref:System.Windows.Data.Binding> is set to `true`, then the binding engine raises the <xref:System.Windows.Controls.Validation.Error?displayProperty=nameWithType> attached event on the element.
Also note that a valid value transfer in either direction (target to source or source to target) clears the <xref:System.Windows.Controls.Validation.Errors%2A?displayProperty=nameWithType> attached property.
If the binding either has an <xref:System.Windows.Controls.ExceptionValidationRule> associated with it, or had the <xref:System.Windows.Data.Binding.ValidatesOnExceptions%2A> property is set to `true` and an exception is thrown when the binding engine sets the source, the binding engine checks to see if there is a <xref:System.Windows.Data.Binding.UpdateSourceExceptionFilter%2A>. You have the option to use the <xref:System.Windows.Data.Binding.UpdateSourceExceptionFilter%2A> callback to provide a custom handler for handling exceptions. If an <xref:System.Windows.Data.Binding.UpdateSourceExceptionFilter%2A> is not specified on the <xref:System.Windows.Data.Binding>, the binding engine creates a <xref:System.Windows.Controls.ValidationError> with the exception and adds it to the <xref:System.Windows.Controls.Validation.Errors%2A?displayProperty=nameWithType> collection of the bound element.
## Debugging mechanism
You can set the attached property <xref:System.Diagnostics.PresentationTraceSources.TraceLevel%2A?displayProperty=nameWithType> on a binding-related object to receive information about the status of a specific binding.
## See also
- <xref:System.Windows.Controls.DataErrorValidationRule>
- [Bind to the results of a LINQ query](../../../framework/wpf/data/how-to-bind-to-the-results-of-a-linq-query.md)
- [Data binding](../../../framework/wpf/advanced/optimizing-performance-data-binding.md)
- [Data binding demo][data-binding-demo]
- [How-to articles](../../../framework/wpf/data/data-binding-how-to-topics.md)
- [Bind to an ADO.NET data source](../../../framework/wpf/data/how-to-bind-to-an-ado-net-data-source.md)
[data-binding-demo]: https://github.com/microsoft/WPF-Samples/tree/master/Sample%20Applications/DataBindingDemo "data binding demo app"
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

@@ -0,0 +1,9 @@
<Application x:Class="bindings.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:bindings"
StartupUri="DataValidation.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace bindings
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
public ObservableCollection<AuctionItem> AuctionItems { get; } = new ObservableCollection<AuctionItem>();
}
}
@@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
namespace bindings
{
public class AuctionItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int CurrentPrice { get; set; } = 0;
public int StartPrice { get; set; } = 50;
public DateTime StartDate { get; set; } = DateTime.Now;
}
}
@@ -0,0 +1,40 @@
<UserControl x:Class="bindings.AutoConvertPropertyToColor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:bindings"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel>
<!-- <BindAutoConvertColor> -->
<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:SDKSample">
<DockPanel.Resources>
<c:MyData x:Key="myDataSource"/>
</DockPanel.Resources>
<DockPanel.DataContext>
<Binding Source="{StaticResource myDataSource}"/>
</DockPanel.DataContext>
<Button Background="{Binding Path=ColorName}"
Width="150" Height="30">
I am bound to be RED!
</Button>
</DockPanel>
<!-- </BindAutoConvertColor> -->
<!-- <BindAutoConvertColorCompactBinding> -->
<DockPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:c="clr-namespace:SDKSample">
<DockPanel.Resources>
<c:MyData x:Key="myDataSource"/>
</DockPanel.Resources>
<Button Background="{Binding Source={StaticResource myDataSource}, Path=ColorName}"
Width="150" Height="30">
I am bound to be RED!
</Button>
</DockPanel>
<!-- </BindAutoConvertColorCompactBinding> -->
</StackPanel>
</UserControl>
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace bindings
{
/// <summary>
/// Interaction logic for DockPanelBindRedExample.xaml
/// </summary>
public partial class AutoConvertPropertyToColor : UserControl
{
public AutoConvertPropertyToColor()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,114 @@
<Window x:Class="bindings.CollectionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:src="clr-namespace:bindings"
xmlns:local="clr-namespace:bindings"
mc:Ignorable="d"
Title="CollectionView" Height="450" Width="800" Loaded="Window_Loaded">
<!-- <CollectionView> -->
<Window.Resources>
<CollectionViewSource
Source="{Binding Source={x:Static Application.Current}, Path=AuctionItems}"
x:Key="listingDataView" />
</Window.Resources>
<!-- </CollectionView> -->
<Grid>
<Grid.Resources>
<!-- <AuctionItemDataTemplate> -->
<DataTemplate DataType="{x:Type src:AuctionItem}">
<Border BorderThickness="1" BorderBrush="Gray"
Padding="7" Name="border" Margin="3" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="86"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Polygon Grid.Row="0" Grid.Column="0" Grid.RowSpan="4"
Fill="Yellow" Stroke="Black" StrokeThickness="1"
StrokeLineJoin="Round" Width="20" Height="20"
Stretch="Fill"
Points="9,2 11,7 17,7 12,10 14,15 9,12 4,15 6,10 1,7 7,7"
Visibility="Hidden" Name="star"/>
<TextBlock Grid.Row="0" Grid.Column="1" Margin="0,0,8,0"
Name="descriptionTitle"
Style="{StaticResource smallTitleStyle}">Description:</TextBlock>
<TextBlock Name="DescriptionDTDataType" Grid.Row="0" Grid.Column="2"
Text="{Binding Path=Description}"
Style="{StaticResource textStyleTextBlock}"/>
<TextBlock Grid.Row="1" Grid.Column="1" Margin="0,0,8,0"
Name="currentPriceTitle"
Style="{StaticResource smallTitleStyle}">Current Price:</TextBlock>
<StackPanel Grid.Row="1" Grid.Column="2" Orientation="Horizontal">
<TextBlock Text="$" Style="{StaticResource textStyleTextBlock}"/>
<TextBlock Name="CurrentPriceDTDataType"
Text="{Binding Path=CurrentPrice}"
Style="{StaticResource textStyleTextBlock}"/>
</StackPanel>
</Grid>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=SpecialFeatures}">
<DataTrigger.Value>
<src:SpecialFeatures>Color</src:SpecialFeatures>
</DataTrigger.Value>
<DataTrigger.Setters>
<Setter Property="BorderBrush" Value="DodgerBlue" TargetName="border" />
<Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
<Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
<Setter Property="BorderThickness" Value="3" TargetName="border" />
<Setter Property="Padding" Value="5" TargetName="border" />
</DataTrigger.Setters>
</DataTrigger>
<DataTrigger Binding="{Binding Path=SpecialFeatures}">
<DataTrigger.Value>
<src:SpecialFeatures>Highlight</src:SpecialFeatures>
</DataTrigger.Value>
<Setter Property="BorderBrush" Value="Orange" TargetName="border" />
<Setter Property="Foreground" Value="Navy" TargetName="descriptionTitle" />
<Setter Property="Foreground" Value="Navy" TargetName="currentPriceTitle" />
<Setter Property="Visibility" Value="Visible" TargetName="star" />
<Setter Property="BorderThickness" Value="3" TargetName="border" />
<Setter Property="Padding" Value="5" TargetName="border" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
<!-- </AuctionItemDataTemplate> -->
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel>
<CheckBox Checked="AddSortCheckBox_Checked">Add Sorting</CheckBox>
<CheckBox Checked="AddFilteringCheckBox_Checked">Add Filtering</CheckBox>
<CheckBox Checked="AddGroupingCheckBox_Checked">Add Grouping</CheckBox>
</StackPanel>
<!-- <ListBoxContentControl> -->
<!-- <ListBoxCollectionView> -->
<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8"
ItemsSource="{Binding Source={StaticResource listingDataView}}" />
<!-- </ListBoxCollectionView> -->
<ContentControl Name="Detail" Grid.Row="3" Grid.ColumnSpan="3"
Content="{Binding Source={StaticResource listingDataView}}"
ContentTemplate="{StaticResource detailsProductListingTemplate}"
Margin="9,0,0,0"/>
<!-- </ListBoxContentControl> -->
</Grid>
</Window>
@@ -0,0 +1,74 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace bindings
{
/// <summary>
/// Interaction logic for CollectionView.xaml
/// </summary>
public partial class CollectionView : Window
{
public CollectionViewSource listingDataView;
public CollectionView()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
listingDataView = (CollectionViewSource)Resources["listingDataView"];
}
// <ListingViewFilter>
private void AddFilteringCheckBox_Checked(object sender, RoutedEventArgs e)
{
if (((CheckBox)sender).IsChecked == true)
listingDataView.Filter += ListingDataView_Filter;
else
listingDataView.Filter -= ListingDataView_Filter;
}
// </ListingViewFilter>
private void AddGroupingCheckBox_Checked(object sender, RoutedEventArgs e)
{
// <ListingGroupCheck>
// This groups the items in the view by the property "Category"
var groupDescription = new PropertyGroupDescription();
groupDescription.PropertyName = "Category";
listingDataView.GroupDescriptions.Add(groupDescription);
// </ListingGroupCheck>
}
// <FilterEvent>
private void ListingDataView_Filter(object sender, FilterEventArgs e)
{
// Start with everything excluded
e.Accepted = false;
// Only inlcude items with a price less than 25
if (e.Item is AuctionItem product && product.CurrentPrice < 25)
e.Accepted = true;
}
// </FilterEvent>
// <AddSortChecked>
private void AddSortCheckBox_Checked(object sender, RoutedEventArgs e)
{
// Sort the items first by Category and then by StartDate
listingDataView.SortDescriptions.Add(new SortDescription("Category", ListSortDirection.Ascending));
listingDataView.SortDescriptions.Add(new SortDescription("StartDate", ListSortDirection.Ascending));
}
// </AddSortChecked>
}
}
@@ -0,0 +1,23 @@
using System;
using System.Windows.Data;
using System.Windows.Media;
namespace bindings
{
// <ColorBrushConverter>
[ValueConversion(typeof(Color), typeof(SolidColorBrush))]
public class ColorBrushConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Color color = (Color)value;
return new SolidColorBrush(color);
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
// </ColorBrushConverter>
}
@@ -0,0 +1,79 @@
<Window x:Class="bindings.DataValidation"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:bindings"
xmlns:src="clr-namespace:bindings"
mc:Ignorable="d"
Title="DataValidation" Height="450" Width="800">
<Window.Resources>
<!-- <ControlTemplate> -->
<ControlTemplate x:Key="validationTemplate">
<DockPanel>
<TextBlock Foreground="Red" FontSize="20">!</TextBlock>
<AdornedElementPlaceholder/>
</DockPanel>
</ControlTemplate>
<!-- </ControlTemplate> -->
<!-- <TextBoxStyle> -->
<Style x:Key="textStyleTextBox" TargetType="TextBox">
<Setter Property="Foreground" Value="#333333" />
<Setter Property="MaxLength" Value="40" />
<Setter Property="Width" Value="392" />
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<!-- </TextBoxStyle> -->
<src:DateConverter x:Key="dateConverter" />
<src:AuctionItem x:Key="item" />
</Window.Resources>
<Grid DataContext="{StaticResource item}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="779*"/>
<ColumnDefinition Width="21*"/>
</Grid.ColumnDefinitions>
<!-- <TextboxStartPrice> -->
<TextBox Name="StartPriceEntryForm" Grid.Row="2"
Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5" Grid.ColumnSpan="2">
<TextBox.Text>
<Binding Path="StartPrice" UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<ExceptionValidationRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- </TextboxStartPrice> -->
<!-- <TextboxStartDate> -->
<TextBox Name="StartDateEntryForm" Grid.Row="3"
Validation.ErrorTemplate="{StaticResource validationTemplate}"
Style="{StaticResource textStyleTextBox}" Margin="8,5,0,5" Grid.ColumnSpan="2">
<TextBox.Text>
<Binding Path="StartDate" UpdateSourceTrigger="PropertyChanged"
Converter="{StaticResource dateConverter}" >
<Binding.ValidationRules>
<src:FutureDateRule />
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
<!-- </TextboxStartDate> -->
</Grid>
</Window>
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace bindings
{
/// <summary>
/// Interaction logic for DataValidation.xaml
/// </summary>
public partial class DataValidation : Window
{
public DataValidation()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Globalization;
using System.Windows.Data;
namespace bindings
{
[ValueConversion(typeof(DateTime), typeof(string))]
public class DateConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
DateTime date = (DateTime)value;
return date.ToShortDateString();
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
string strValue = value.ToString();
DateTime resultDateTime;
if (DateTime.TryParse(strValue, out resultDateTime))
{
return resultDateTime;
}
return value;
}
}
}
@@ -0,0 +1,15 @@
<UserControl x:Class="bindings.EmptyBinding"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:bindings"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<StackPanel>
<!-- <EmptyBinding> -->
<ListBox ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="true"/>
<!-- </EmptyBinding> -->
</StackPanel>
</UserControl>
@@ -0,0 +1,26 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace bindings
{
/// <summary>
/// Interaction logic for EmptyBinding.xaml
/// </summary>
public partial class EmptyBinding : UserControl
{
public EmptyBinding()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Windows.Controls;
namespace bindings
{
// <FutureDateRule>
public class FutureDateRule : ValidationRule
{
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
// Test if date is valid
if (DateTime.TryParse(value.ToString(), out DateTime date))
{
// Date is not in the future, fail
if (DateTime.Now > date)
return new ValidationResult(false, "Please enter a date in the future.");
}
else
{
// Date is not a valid date, fail
return new ValidationResult(false, "Value is not a valid date.");
}
// Date is valid and in the future, pass
return ValidationResult.ValidResult;
}
}
// </FutureDateRule>
}
@@ -0,0 +1,12 @@
<Window x:Class="bindings.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:bindings"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
@@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace bindings
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,26 @@
using System.Windows.Controls;
using System.Windows.Data;
using SDKSample;
namespace bindings
{
class ManualBinding
{
public TextBox myText;
public void BindTextBox()
{
// <CodeOnlyBinding>
// Make a new source
var myDataObject = new MyData();
var myBinding = new Binding("ColorName")
{
Source = myDataObject
};
// Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding);
// </CodeOnlyBinding>
}
}
}
@@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace SDKSample
{
class MyData
{
public string ColorName => "Red";
}
}
@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace bindings
{
public enum SpecialFeatures
{
None,
Color,
Highlight
}
}
@@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<UseWpf>true</UseWpf>
</PropertyGroup>
</Project>
@@ -0,0 +1,9 @@
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:bindings"
StartupUri="CollectionView.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -0,0 +1,10 @@
Imports System.Collections.ObjectModel
Class Application
' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
' can be handled in this file.
Public ReadOnly Property AuctionItems As ObservableCollection(Of AuctionItem) = New ObservableCollection(Of AuctionItem)
End Class
@@ -0,0 +1,10 @@
Imports System.ComponentModel
Public Class AuctionItem
Implements INotifyPropertyChanged
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Public CurrentPrice As Integer
End Class
@@ -0,0 +1,33 @@
<Window x:Class="CollectionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:bindings"
mc:Ignorable="d"
Title="CollectionView" Height="450" Width="800" Loaded="Window_Loaded">
<!-- <CollectionView> -->
<Window.Resources>
<CollectionViewSource
Source="{Binding Source={x:Static Application.Current}, Path=AuctionItems}"
x:Key="listingDataView" />
</Window.Resources>
<!-- </CollectionView> -->
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<StackPanel>
<CheckBox Checked="AddSortCheckBox_Checked">Add Sorting</CheckBox>
<CheckBox Checked="AddFilteringCheckBox_Checked">Add Filtering</CheckBox>
<CheckBox Checked="AddGroupingCheckBox_Checked">Add Grouping</CheckBox>
</StackPanel>
<!-- <ListBoxCollectionView> -->
<ListBox Name="Master" Grid.Row="2" Grid.ColumnSpan="3" Margin="8"
ItemsSource="{Binding Source={StaticResource listingDataView}}" />
<!-- </ListBoxCollectionView> -->
</Grid>
</Window>
@@ -0,0 +1,58 @@
Imports System.ComponentModel
Public Class CollectionView
Public listingDataView As CollectionViewSource
Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs)
listingDataView = CType(Resources("listingDataView"), CollectionViewSource)
End Sub
' <ListingViewFilter>
Private Sub AddFilteringCheckBox_Checked(sender As Object, e As RoutedEventArgs)
Dim checkBox = DirectCast(sender, CheckBox)
If checkBox.IsChecked = True Then
AddHandler listingDataView.Filter, AddressOf ListingDataView_Filter
Else
RemoveHandler listingDataView.Filter, AddressOf ListingDataView_Filter
End If
End Sub
' </ListingViewFilter>
Private Sub AddGroupingCheckBox_Checked(sender As Object, e As RoutedEventArgs)
' <ListingGroupCheck>
' This groups the items in the view by the property "Category"
Dim groupDescription = New PropertyGroupDescription()
groupDescription.PropertyName = "Category"
listingDataView.GroupDescriptions.Add(groupDescription)
' </ListingGroupCheck>
End Sub
' <FilterEvent>
Private Sub ListingDataView_Filter(sender As Object, e As FilterEventArgs)
' Start with everything excluded
e.Accepted = False
Dim product As AuctionItem = TryCast(e.Item, AuctionItem)
If product IsNot Nothing Then
' Only include products with prices lower than 25
If product.CurrentPrice < 25 Then e.Accepted = True
End If
End Sub
' </FilterEvent>
' <AddSortChecked>
Private Sub AddSortCheckBox_Checked(sender As Object, e As RoutedEventArgs)
' Sort the items first by Category And then by StartDate
listingDataView.SortDescriptions.Add(New SortDescription("Category", ListSortDirection.Ascending))
listingDataView.SortDescriptions.Add(New SortDescription("StartDate", ListSortDirection.Ascending))
End Sub
' </AddSortChecked>
End Class
@@ -0,0 +1,14 @@
' <ColorBrushConverter>
<ValueConversion(GetType(Color), GetType(SolidColorBrush))>
Public Class ColorBrushConverter
Implements IValueConverter
Public Function Convert(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.Convert
Dim color As Color = CType(value, Color)
Return New SolidColorBrush(color)
End Function
Public Function ConvertBack(ByVal value As Object, ByVal targetType As Type, ByVal parameter As Object, ByVal culture As System.Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
Return Nothing
End Function
End Class
' </ColorBrushConverter>
@@ -0,0 +1,30 @@
Imports System.Globalization
' <FutureDateRule>
Public Class FutureDateRule
Inherits ValidationRule
Public Overrides Function Validate(value As Object, cultureInfo As CultureInfo) As ValidationResult
Dim inputDate As Date
' Test if date is valid
If Date.TryParse(value.ToString, inputDate) Then
' Date is not in the future, fail
If Date.Now > inputDate Then
Return New ValidationResult(False, "Please enter a date in the future.")
End If
Else
' // Date Is Not a valid date, fail
Return New ValidationResult(False, "Value is not a valid date.")
End If
' Date is valid and in the future, pass
Return ValidationResult.ValidResult
End Function
End Class
' </FutureDateRule>
@@ -0,0 +1,12 @@
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:bindings"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
</Grid>
</Window>
@@ -0,0 +1,3 @@
Class MainWindow
End Class
@@ -0,0 +1,19 @@
Imports bindings.SDKSample
Public Class ManualBinding
Public myText As TextBox
Public Sub BindTextBox()
' <CodeOnlyBinding>
' Make a New source
Dim myDataObject As New MyData
Dim myBinding As New Binding("ColorName")
myBinding.Source = myDataObject
' Bind the data source to the TextBox control's Text dependency property
myText.SetBinding(TextBlock.TextProperty, myBinding)
' </CodeOnlyBinding>
End Sub
End Class
@@ -0,0 +1,9 @@
Namespace SDKSample
Public Class MyData
Public ReadOnly Property ColorName As String = "Red"
End Class
End Namespace
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>bindings</RootNamespace>
<UseWpf>true</UseWpf>
</PropertyGroup>
<ItemGroup>
<Import Include="System.Windows" />
<Import Include="System.Windows.Controls" />
<Import Include="System.Windows.Data" />
<Import Include="System.Windows.Documents" />
<Import Include="System.Windows.Input" />
<Import Include="System.Windows.Media" />
<Import Include="System.Windows.Media.Imaging" />
<Import Include="System.Windows.Navigation" />
<Import Include="System.Windows.Shapes" />
</ItemGroup>
</Project>
Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

@@ -0,0 +1,14 @@
// // Copyright (c) Microsoft. All rights reserved.
// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Windows;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
@@ -0,0 +1,18 @@
<!--<AppResources>-->
<Application x:Class="IntroToStylingAndTemplating.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
StartupUri="WindowExplicitStyle.xaml">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
<!--</AppResources>-->
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>IntroToStylingAndTemplating</RootNamespace>
<UseWpf>true</UseWpf>
<AssemblyName>IntroToStylingAndTemplating</AssemblyName>
</PropertyGroup>
<ItemGroup>
<None Include="images\flower1.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="images\flower2.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="images\leaf1.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="images\leaf2.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="images\winter1.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,27 @@
// // Copyright (c) Microsoft. All rights reserved.
// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Windows;
using System.Windows.Data;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private PhotoList _photos;
public MainWindow()
{
InitializeComponent();
}
private void WindowLoaded(object sender, RoutedEventArgs e)
{
_photos = (PhotoList) (Resources["MyPhotos"] as ObjectDataProvider).Data;
_photos.Path = "images";
}
}
}
@@ -0,0 +1,106 @@
<Window x:Class="IntroToStylingAndTemplating.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Style Intro Sample" Loaded="WindowLoaded" SizeToContent="WidthAndHeight">
<Window.Resources>
<ObjectDataProvider x:Key="MyPhotos" ObjectType="{x:Type local:PhotoList}"/>
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named style" with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<!--Horizontal ListBox Control Template-->
<Style TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center"
IsItemsHost="True"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--DataTemplate to display Photos as images
instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
<Border Margin="3">
<Image Source="{Binding Source}"/>
</Border>
</DataTemplate>
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" Value="1.0" />
</Trigger.Setters>
</Trigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight"
To="90" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Margin="10">
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
</StackPanel>
</Window>
@@ -0,0 +1,19 @@
// // Copyright (c) Microsoft. All rights reserved.
// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace IntroToStylingAndTemplating
{
// <PhotoClass>
public class Photo
{
public Photo(string path)
{
Source = path;
}
public string Source { get; }
public override string ToString() => Source;
}
// </PhotoClass>
}
@@ -0,0 +1,55 @@
// // Copyright (c) Microsoft. All rights reserved.
// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.ObjectModel;
using System.IO;
namespace IntroToStylingAndTemplating
{
public class PhotoList : ObservableCollection<Photo>
{
private DirectoryInfo _directory;
public PhotoList()
{
}
public PhotoList(string path) : this(new DirectoryInfo(path))
{
}
public PhotoList(DirectoryInfo directory)
{
_directory = directory;
Update();
}
public string Path
{
set
{
_directory = new DirectoryInfo(value);
Update();
}
get { return _directory.FullName; }
}
public DirectoryInfo Directory
{
set
{
_directory = value;
Update();
}
get { return _directory; }
}
private void Update()
{
foreach (var f in _directory.GetFiles("*.jpg"))
{
Add(new Photo(f.FullName));
}
}
}
}
@@ -0,0 +1,25 @@
<Window x:Class="IntroToStylingAndTemplating.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800">
<!--<SnippetDefaultTextBlockStyle>-->
<Window.Resources>
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
<!--</SnippetDefaultTextBlockStyle>-->
<!--<SnippetTextBlocks>-->
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
<!--</SnippetTextBlocks>-->
</Window>
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,44 @@
<Window x:Class="IntroToStylingAndTemplating.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Window2" Height="450" Width="800" Loaded="Window_Loaded">
<!--<SnippetDefaultTextBlockStyleBasedOn>-->
<Window.Resources>
<!-- .... other resources .... -->
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!--A Style that extends the previous TextBlock Style with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<!--</SnippetDefaultTextBlockStyleBasedOn>-->
<!--<SnippetTextBlocksExplicit>-->
<StackPanel>
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
<!--</SnippetTextBlocksExplicit>-->
</Window>
@@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for Window2.xaml
/// </summary>
public partial class Window2 : Window
{
public Window2()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// <SnippetSetStyleCode>
textblock1.Style = (Style)Resources["TitleText"];
// </SnippetSetStyleCode>
}
}
}
@@ -0,0 +1,20 @@
<Window x:Class="IntroToStylingAndTemplating.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Window3" Height="450" Width="800">
<Window.Resources>
<ObjectDataProvider x:Key="MyPhotos" ObjectType="{x:Type local:PhotoList}"/>
</Window.Resources>
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
<!--<SnippetListBox>-->
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
<!--</SnippetListBox>-->
</StackPanel>
</Window>
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for Window3.xaml
/// </summary>
public partial class Window3 : Window
{
public Window3()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,26 @@
<Window x:Class="IntroToStylingAndTemplating.Window4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Window4" Height="450" Width="800">
<!--<SnippetDataTemplate>-->
<Window.Resources>
<!-- .... other resources .... -->
<!--DataTemplate to display Photos as images
instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
<Border Margin="3">
<Image Source="{Binding Source}"/>
</Border>
</DataTemplate>
</Window.Resources>
<!--</SnippetDataTemplate>-->
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
</Window>
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for Window4.xaml
/// </summary>
public partial class Window4 : Window
{
public Window4()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,30 @@
<Window x:Class="IntroToStylingAndTemplating.Window5"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Window5" Height="450" Width="800">
<!--<SnippetPropertyTrigger>-->
<Window.Resources>
<!-- .... other resources .... -->
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" Value="1.0" />
</Trigger.Setters>
</Trigger>
</Style.Triggers>
</Style>
</Window.Resources>
<!--</SnippetPropertyTrigger>-->
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
</Window>
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for Window5.xaml
/// </summary>
public partial class Window5 : Window
{
public Window5()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,53 @@
<Window x:Class="IntroToStylingAndTemplating.Window6"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Window6" Height="450" Width="800">
<Window.Resources>
<!-- .... other resources .... -->
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<!--<SnippetStyleEventTriggers>-->
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" Value="1.0" />
</Trigger.Setters>
</Trigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight"
To="90" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
<!--</SnippetStyleEventTriggers>-->
</Style>
</Window.Resources>
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
</Window>
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for Window6.xaml
/// </summary>
public partial class Window6 : Window
{
public Window6()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,25 @@
<Window x:Class="IntroToStylingAndTemplating.ExplicitStyle"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Height="100" Width="300"
Title="Style Intro Sample">
<!--<ExplicitStyleDeclare>-->
<Window.Resources>
<Style x:Key="TitleText" TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
<!--</ExplicitStyleDeclare>-->
<!--<ExplicitStyleReference>-->
<StackPanel>
<TextBlock Style="{StaticResource TitleText}">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
<!--</ExplicitStyleReference>-->
</Window>
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for ExplicitStyle.xaml
/// </summary>
public partial class ExplicitStyle : Window
{
public ExplicitStyle()
{
InitializeComponent();
}
}
}
@@ -0,0 +1,20 @@
<!--<WindowResources>-->
<Window x:Class="IntroToStylingAndTemplating.WindowSingleResource"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="WindowSingleResource" Height="450" Width="800">
<Window.Resources>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</Window.Resources>
<Grid />
</Window>
<!--</WindowResources>-->
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for WindowSingleResource.xaml
/// </summary>
public partial class WindowSingleResource : Window
{
public WindowSingleResource()
{
InitializeComponent();
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

@@ -0,0 +1,9 @@
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>
@@ -0,0 +1,6 @@
Class Application
' Application-level events, such as Startup, Exit, and DispatcherUnhandledException
' can be handled in this file.
End Class
@@ -0,0 +1,33 @@
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded">
<Window.Resources>
<!-- .... other resources .... -->
<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named style" with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TextBlock Name="textblock1">My Pictures</TextBlock>
</Grid>
</Window>
@@ -0,0 +1,7 @@
Class MainWindow
Private Sub Window_Loaded(sender As Object, e As Windows.RoutedEventArgs)
'<SnippetSetStyleCode>
textblock1.Style = CType(Resources("TitleText"), Windows.Style)
'</SnippetSetStyleCode>
End Sub
End Class
@@ -0,0 +1,13 @@
' <PhotoClass>
Public Class Photo
Sub New(ByVal path As String)
Source = path
End Sub
Public ReadOnly Property Source As String
Public Overrides Function ToString() As String
Return Source
End Function
End Class
' </PhotoClass>
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>IntroToStylingAndTemplating</RootNamespace>
<UseWpf>true</UseWpf>
<AssemblyName>IntroToStylingAndTemplating</AssemblyName>
</PropertyGroup>
</Project>
@@ -0,0 +1,14 @@
// // Copyright (c) Microsoft. All rights reserved.
// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Windows;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}
@@ -0,0 +1,18 @@
<!--<AppResources>-->
<Application x:Class="IntroToStylingAndTemplating.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
StartupUri="WindowExplicitStyle.xaml">
<Application.Resources>
<ResourceDictionary>
<Style x:Key="Header1" TargetType="TextBlock">
<Setter Property="FontSize" Value="15" />
<Setter Property="FontWeight" Value="ExtraBold" />
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
<!--</AppResources>-->
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>netcoreapp3.1</TargetFramework>
<RootNamespace>IntroToStylingAndTemplating</RootNamespace>
<UseWpf>true</UseWpf>
<AssemblyName>IntroToStylingAndTemplating</AssemblyName>
</PropertyGroup>
<ItemGroup>
<None Include="images\flower1.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="images\flower2.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="images\leaf1.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="images\leaf2.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Include="images\winter1.jpg">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,27 @@
// // Copyright (c) Microsoft. All rights reserved.
// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Windows;
using System.Windows.Data;
namespace IntroToStylingAndTemplating
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private PhotoList _photos;
public MainWindow()
{
InitializeComponent();
}
private void WindowLoaded(object sender, RoutedEventArgs e)
{
_photos = (PhotoList) (Resources["MyPhotos"] as ObjectDataProvider).Data;
_photos.Path = "images";
}
}
}
@@ -0,0 +1,106 @@
<Window x:Class="IntroToStylingAndTemplating.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Style Intro Sample" Loaded="WindowLoaded" SizeToContent="WidthAndHeight">
<Window.Resources>
<ObjectDataProvider x:Key="MyPhotos" ObjectType="{x:Type local:PhotoList}"/>
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
<!--A Style that extends the previous TextBlock Style-->
<!--This is a "named style" with an x:Key of TitleText-->
<Style BasedOn="{StaticResource {x:Type TextBlock}}"
TargetType="TextBlock"
x:Key="TitleText">
<Setter Property="FontSize" Value="26"/>
<Setter Property="Foreground">
<Setter.Value>
<LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
<LinearGradientBrush.GradientStops>
<GradientStop Offset="0.0" Color="#90DDDD" />
<GradientStop Offset="1.0" Color="#5BFFFF" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
<!--Horizontal ListBox Control Template-->
<Style TargetType="ListBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBox">
<Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}">
<ScrollViewer HorizontalScrollBarVisibility="Auto">
<StackPanel Orientation="Horizontal"
VerticalAlignment="Center"
HorizontalAlignment="Center"
IsItemsHost="True"/>
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--DataTemplate to display Photos as images
instead of text strings of Paths-->
<DataTemplate DataType="{x:Type local:Photo}">
<Border Margin="3">
<Image Source="{Binding Source}"/>
</Border>
</DataTemplate>
<Style TargetType="ListBoxItem">
<Setter Property="Opacity" Value="0.5" />
<Setter Property="MaxHeight" Value="75" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Trigger.Setters>
<Setter Property="Opacity" Value="1.0" />
</Trigger.Setters>
</Trigger>
<EventTrigger RoutedEvent="Mouse.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:0.2"
Storyboard.TargetProperty="MaxHeight"
To="90" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Mouse.MouseLeave">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Duration="0:0:1"
Storyboard.TargetProperty="MaxHeight" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<StackPanel Margin="10">
<TextBlock Style="{StaticResource TitleText}" Name="textblock1">My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
<ListBox ItemsSource="{Binding Source={StaticResource MyPhotos}}"
Background="Silver" Width="600" Margin="10" SelectedIndex="0"/>
</StackPanel>
</Window>
@@ -0,0 +1,19 @@
// // Copyright (c) Microsoft. All rights reserved.
// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace IntroToStylingAndTemplating
{
// <PhotoClass>
public class Photo
{
public Photo(string path)
{
Source = path;
}
public string Source { get; }
public override string ToString() => Source;
}
// </PhotoClass>
}
@@ -0,0 +1,55 @@
// // Copyright (c) Microsoft. All rights reserved.
// // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System.Collections.ObjectModel;
using System.IO;
namespace IntroToStylingAndTemplating
{
public class PhotoList : ObservableCollection<Photo>
{
private DirectoryInfo _directory;
public PhotoList()
{
}
public PhotoList(string path) : this(new DirectoryInfo(path))
{
}
public PhotoList(DirectoryInfo directory)
{
_directory = directory;
Update();
}
public string Path
{
set
{
_directory = new DirectoryInfo(value);
Update();
}
get { return _directory.FullName; }
}
public DirectoryInfo Directory
{
set
{
_directory = value;
Update();
}
get { return _directory; }
}
private void Update()
{
foreach (var f in _directory.GetFiles("*.jpg"))
{
Add(new Photo(f.FullName));
}
}
}
}
@@ -0,0 +1,25 @@
<Window x:Class="IntroToStylingAndTemplating.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:IntroToStylingAndTemplating"
mc:Ignorable="d"
Title="Window1" Height="450" Width="800">
<!--<SnippetDefaultTextBlockStyle>-->
<Window.Resources>
<!--A Style that affects all TextBlocks-->
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Comic Sans MS"/>
<Setter Property="FontSize" Value="14"/>
</Style>
</Window.Resources>
<!--</SnippetDefaultTextBlockStyle>-->
<!--<SnippetTextBlocks>-->
<StackPanel>
<TextBlock>My Pictures</TextBlock>
<TextBlock>Check out my new pictures!</TextBlock>
</StackPanel>
<!--</SnippetTextBlocks>-->
</Window>

Some files were not shown because too many files have changed in this diff Show More