This commit is contained in:
Beatriz Stollnitz 2019-08-05 17:58:14 -07:00
Родитель f71cd46116
Коммит d3820e4483
14 изменённых файлов: 640 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,78 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{281A8A8D-1C26-492C-8798-07EE17F066C6}</ProjectGuid>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<RootNamespace>AsynchronousBinding</RootNamespace>
<AssemblyName>AsynchronousBinding</AssemblyName>
<WarningLevel>4</WarningLevel>
<OutputType>winexe</OutputType>
<ApplicationVersion>1.0.0.*</ApplicationVersion>
<!-- Most people will use Publish dialog in Visual Studio to increment this -->
<BootstrapperEnabled>false</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>.\bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugSymbols>false</DebugSymbols>
<Optimize>true</Optimize>
<OutputPath>.\bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="UIAutomationProvider" />
<Reference Include="UIAutomationTypes" />
<Reference Include="ReachFramework" />
<Reference Include="System.Printing" />
<Reference Include="System.ServiceModel" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.IdentityModel" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="MyApp.xaml" />
<Page Include="Window1.xaml" />
<Compile Include="MyApp.xaml.cs">
<DependentUpon>MyApp.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Window1.xaml.cs">
<DependentUpon>Window1.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
<AppDesigner Include="Properties\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

Просмотреть файл

@ -0,0 +1,20 @@

Microsoft Visual Studio Solution File, Format Version 9.00
# Visual Studio 2005
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AsynchronousBinding", "AsynchronousBinding.csproj", "{281A8A8D-1C26-492C-8798-07EE17F066C6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{281A8A8D-1C26-492C-8798-07EE17F066C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{281A8A8D-1C26-492C-8798-07EE17F066C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{281A8A8D-1C26-492C-8798-07EE17F066C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{281A8A8D-1C26-492C-8798-07EE17F066C6}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal

Двоичные данные
24-AsynchronousBinding/AsynchronousBinding/AsynchronousBinding.suo Normal file

Двоичный файл не отображается.

Просмотреть файл

@ -0,0 +1,9 @@
<Application x:Class="AsynchronousBinding.MyApp"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml"
>
<Application.Resources>
</Application.Resources>
</Application>

Просмотреть файл

@ -0,0 +1,17 @@
using System;
using System.Windows;
using System.Data;
using System.Xml;
using System.Configuration;
namespace AsynchronousBinding
{
/// <summary>
/// Interaction logic for MyApp.xaml
/// </summary>
public partial class MyApp : Application
{
}
}

Просмотреть файл

@ -0,0 +1,54 @@
#region Using directives
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Resources;
using System.Globalization;
using System.Windows;
using System.Runtime.InteropServices;
#endregion
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("AsynchronousBinding")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("AsynchronousBinding")]
[assembly: AssemblyCopyright("Copyright @ 2006")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: ComVisible(false)]
//In order to begin building localizable applications, set
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
//inside a <PropertyGroup>. For example, if you are using US english
//in your source files, set the <UICulture> to en-US. Then uncomment
//the NeutralResourceLanguage attribute below. Update the "en-US" in
//the line below to match the UICulture setting in the project file.
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("1.0.*")]

Просмотреть файл

@ -0,0 +1,70 @@
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------
namespace AsynchronousBinding.Properties
{
using System;
using System.IO;
using System.Resources;
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the Strongly Typed Resource Builder
// class via a tool like ResGen or Visual Studio.NET.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
class Resources
{
private static System.Resources.ResourceManager _resMgr;
private static System.Globalization.CultureInfo _resCulture;
/*FamANDAssem*/
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public static System.Resources.ResourceManager ResourceManager
{
get
{
if ((_resMgr == null))
{
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Resources", typeof(Resources).Assembly);
_resMgr = temp;
}
return _resMgr;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
public static System.Globalization.CultureInfo Culture
{
get
{
return _resCulture;
}
set
{
_resCulture = value;
}
}
}
}

Просмотреть файл

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

Просмотреть файл

@ -0,0 +1,42 @@
//------------------------------------------------------------------------------
// <autogenerated>
// This code was generated by a tool.
// Runtime Version:2.0.50727.42
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </autogenerated>
//------------------------------------------------------------------------------
namespace AsynchronousBinding.Properties
{
public partial class Settings : System.Configuration.ApplicationSettingsBase
{
private static Settings m_Value;
private static object m_SyncObject = new object();
public static Settings Value
{
get
{
if ((Settings.m_Value == null))
{
System.Threading.Monitor.Enter(Settings.m_SyncObject);
if ((Settings.m_Value == null))
{
try
{
Settings.m_Value = new Settings();
}
finally
{
System.Threading.Monitor.Exit(Settings.m_SyncObject);
}
}
}
return Settings.m_Value;
}
}
}
}

Просмотреть файл

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='iso-8859-1'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

Просмотреть файл

@ -0,0 +1,34 @@
<Window x:Class="AsynchronousBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="AsynchronousBinding"
xmlns:local="clr-namespace:AsynchronousBinding"
SizeToContent="WidthAndHeight"
>
<Window.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="animatedRect"
Storyboard.TargetProperty="Width"
From="20" To="200" Duration="0:0:2"
AutoReverse="True" RepeatBehavior="Forever" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Window.Triggers>
<Border Margin="30" BorderBrush="Blue" BorderThickness="2" Padding="10">
<StackPanel>
<Rectangle Name="animatedRect" Width="20" Height="20" Fill="IndianRed" Margin="10"/>
<Button Content="Bind to slow data source (synchronous)" Click="SlowDataSourceSync" />
<TextBlock Name="tbSlowDSSync" Margin="5"/>
<Button Content="Bind to slow data source (asynchronous)" Click="SlowDataSourceAsync" />
<TextBlock Name="tbSlowDSAsync" Margin="5"/>
<Button Content="Bind to slow property of data source (synchronous)" Click="SlowPropertySync" />
<TextBlock Name="tbSlowPropSync" Margin="5"/>
<Button Content="Bind to slow property of data source (asynchronous)" Click="SlowPropertyAsync" />
<TextBlock Name="tbSlowPropAsync" Margin="5"/>
</StackPanel>
</Border>
</Window>

Просмотреть файл

@ -0,0 +1,109 @@
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Threading;
using System.Net;
namespace AsynchronousBinding
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}
private void SlowDataSourceSync(object sender, RoutedEventArgs args)
{
((Button)sender).IsEnabled = false;
ObjectDataProvider odp = new ObjectDataProvider();
//odp.IsAsynchronous = false; - this is the default
odp.ObjectType = typeof(SlowDataSource);
Binding b = new Binding();
b.Source = odp;
b.Path = new PropertyPath("Property");
tbSlowDSSync.SetBinding(TextBlock.TextProperty, b);
}
private void SlowDataSourceAsync(object sender, RoutedEventArgs args)
{
((Button)sender).IsEnabled = false;
ObjectDataProvider odp = new ObjectDataProvider();
odp.IsAsynchronous = true;
odp.ObjectType = typeof(SlowDataSource);
Binding b = new Binding();
b.Source = odp;
b.Path = new PropertyPath("Property");
tbSlowDSAsync.SetBinding(TextBlock.TextProperty, b);
}
private void SlowPropertySync(object sender, RoutedEventArgs args)
{
((Button)sender).IsEnabled = false;
DataSource source = new DataSource();
Binding b = new Binding();
b.Source = source;
//b.IsAsync = false; - this is the default
b.Path = new PropertyPath("SlowProperty");
tbSlowPropSync.SetBinding(TextBlock.TextProperty, b);
}
private void SlowPropertyAsync(object sender, RoutedEventArgs args)
{
((Button)sender).IsEnabled = false;
DataSource source = new DataSource();
Binding b = new Binding();
b.Source = source;
b.IsAsync = true;
b.Path = new PropertyPath("SlowProperty");
tbSlowPropAsync.SetBinding(TextBlock.TextProperty, b);
}
}
public class SlowDataSource
{
private string property;
public string Property
{
get { return property; }
set { property = value; }
}
public SlowDataSource()
{
Thread.Sleep(3000);
this.property = "Slow data source";
}
}
public class DataSource
{
private string slowProperty;
public string SlowProperty
{
get
{
Thread.Sleep(3000);
return slowProperty;
}
set { slowProperty = value; }
}
public DataSource()
{
this.slowProperty = "Slow property";
}
}
}

Двоичные данные
24-AsynchronousBinding/Images/24AsynchronousBinding.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 14 KiB

Просмотреть файл

@ -0,0 +1,83 @@
# How to control whether my Binding is synchronous or asynchronous
I will explain in this post how you can control whether your binding is synchronous or asynchronous. As you know, a synchronous binding will freeze the UI while it's fetching the data, while an asynchronous binding will start a second thread and keep the UI responsive. Understanding the default behavior will allow you to make the best decision for your particular scenario, whether that is keeping or changing it.
I will distinguish two very different scenarios in this sample:
- The whole data source takes a while to be available. For example, you are binding to a web service, an RSS feed, or an external XML file. In this case, the actual creation of the data object is not immediate.
- A property in your data source is slow. In this scenario, the data source is created very quickly, but one of its properties takes a while to return from the getter (for example, the property uses an HttpWebRequest). Note that the .NET guidelines recommend against having slow code in a property getter, and so we actually went back and forth about whether we should support this scenario.
## Slow data source
I talked in an <a href="http://www.zagstudio.com/blog/438">earlier post</a> about ObjectDataPovider, and mentioned that you will need it if you want to retrieve your data asynchronously. Well, here is the scenario where you would want to use it: when your whole data source is slow. I simulated a slow data source with the following code:
public class SlowDataSource
{
private string property;
public string Property
{
get { return property; }
set { property = value; }
}
public SlowDataSource()
{
Thread.Sleep(3000);
this.property = "Slow data source";
}
}
ObjectDataProvider has an IsAsynchronous property, which when set to true, tells Avalon to create the data source object in a worker thread. Keep in mind that by default the IsAsynchronous property is false, so you have to remember to set it to true. The following code shows how to create the ObjectDataProvider and Binding such that binding to the SlowDataSource object will not block the UI thread:
ObjectDataProvider odp = new ObjectDataProvider();
odp.IsAsynchronous = true;
odp.ObjectType = typeof(SlowDataSource);
Binding b = new Binding();
b.Source = odp;
b.Path = new PropertyPath("Property");
tbSlowDSSync.SetBinding(TextBlock.TextProperty, b);
We made ObjectDataProvider synchronous by default because we typically expect object sources to be quick to retrieve. XmlDataProvider works similarly, except the IsAsynchronous property is set to true by default. We made it asynchronous by default because we expect it to be used mostly when binding to external XML files and RSS feeds, which can take a while to get to. If you only have 5 lines of XML embedded in your XAML page, however, you may want to set the IsAsynchronous property to false.
!!Slow property in fast data source
In this second scenario, we get a handle to the data source pretty quickly, but one of its properties can be quite slow to retrieve. Here is a simulated sample of such a data source:
public class DataSource
{
private string slowProperty;
public string SlowProperty
{
get
{
Thread.Sleep(3000);
return slowProperty;
}
set { slowProperty = value; }
}
public DataSource()
{
this.slowProperty = "Slow property";
}
}
In this scenario, we don't have to use ObjectDataProvider anymore. We can create the object in the same thread as the application, and we may want to bind to other fast properties in this same data source synchronously. We want to bind to just that one slow property asynchronously, so we don't block the UI. To achieve this, we can use the IsAsync property of Binding, as you can see in the following code snippet:
DataSource source = new DataSource();
Binding b = new Binding();
b.Source = source;
b.IsAsync = true;
b.Path = new PropertyPath("SlowProperty");
tbSlowPropAsync.SetBinding(TextBlock.TextProperty, b);
The IsAsync property is false by default, so you have to remember to set it to true in this scenario. We decided to make it false by default because slow setters are bad practice, so we don't expect this to be a common scenario.
Note that you could just as easily create asynchronous data providers or bindings from within XAML; I made them in code because a few people have asked for examples.
Below is a screenshot of the application. The rectangle on top is animating so you can clearly see the UI freeze when doing the synchronous bindings.
![](Images/24AsynchronousBinding.png)