Binding的Source从何而来?

I. Binding to Object

1. Binding data using ObjectDataProvider

AC:Let’s say there is a CLR based data bound object that you are trying to implement. For example a collection of Tool objects, e.g.

  • An Object called Tool that contains a bunch of properties that we want to bind (in this case it just contains a description)
  • A Collection of Tool objects(ToolsCollection); for example to populate a list box etc
  • A Factory to get the reference of ToolsCollection objects which have collection<Tools>
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CLRDataBinding
{
    public class Tool : INotifyPropertyChanged
    {
        private string _description = "";
        public string Description
        {
            get
            {
                return _description;
            }
            set
            {
                if (_description != value)
                {
                    _description = value;
                    NotifyPropertyChanged("Description");
                }
            }
        }
        public Tool(string description)
        {
            _description = description;
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void NotifyPropertyChanged(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

    }
}
View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.ObjectModel;

namespace CLRDataBinding
{
    public class ToolsCollection : ObservableCollection<Tool>
    {
        public ToolsCollection()
        {
            CreateToolsData();
        }

        private void CreateToolsData()
        {
            for (int loop = 0; loop < 1000; loop++)
            {
                this.Add(new Tool("Tool " + loop.ToString()));
            }
        }
    }
}
View Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CLRDataBinding
{
    public class Factory
    {
        public ToolsCollection MyToolsCollection
        {
            get { return new ToolsCollection(); }
        }
    }
}
View Code
<Window x:Class="CLRDataBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:clr="clr-namespace:CLRDataBinding"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Window.Resources>
        <ObjectDataProvider x:Key="FactoryDP" ObjectType="{x:Type clr:Factory}" />
        <DataTemplate x:Key="ToolItemTemplate">
            <StackPanel>
                <TextBlock Text="{Binding Description}" />
            </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <Grid>
        <ListBox ItemTemplate="{StaticResource ToolItemTemplate}" ItemsSource="{Binding Path=MyToolsCollection, Source={StaticResource FactoryDP}}" />
    </Grid>
</Window>
View Code

 

之前一篇文章 对象数据绑定 里提到三个例子,第一个例子用了ObjectDataProvider没有用DataContext,第二个例子用了DataContext没有用 ObjectDataProvider,第三个例子既用了ObjectDataProvider也用了DataContext,但没有提到它们的区别,正 好在Beatriz Costa的blog上看到一篇好文章解释了为什么需要 ObjectDataProvider的问题。

ObjectDataProvider能实现四个特殊功能:

1. 传递参数到构造函数中

使用下面的XAML语句定义一个ObjectDataProvider,它会自动调用MySource类的默认构造函数初始化类
<ObjectDataProvider ObjectType="{x:Type local:MySource}" x:Key="odp1"/>
如果MySource类的构造函数允许传入参数的话,就可以这样定义ObjectDataProvider:
<ObjectDataProvider ObjectType="{x:Type local:MySource}" x:Key="odp1">
  <ObjectDataProvider.ConstructorParameters>
    <system:String>Jupiter</system:String>
  </ObjectDataProvider.ConstructorParameters>
</ObjectDataProvider>

2. 绑定到方法

ObjectDataProvider 除了 ObjectType的属性外还有MethodName的属性,MethodName属性将ObjectDataProvider绑定到方法,相当于是对数据源的包装,另外也可以定义方法的传入参数:
<ObjectDataProvider ObjectInstance="{StaticResource odp1}" MethodName="WeightOnPlanet" x:Key="odp2">
  <ObjectDataProvider.MethodParameters>
    <system:Double>95</system:Double>
  </ObjectDataProvider.MethodParameters>
</ObjectDataProvider>

3. 替换数据对象

和使用自己在resource中定义对象不同,ObjectDataProvider可以使里很简单的更换绑定的数据对象,只需要更换一下绑定的数据对象的名字。而使用自己在resource中定义对象,即使定义了相同的x:Key也不能达到自动更新的目的。
另,这里使用DataContext也能达到与ObjectDataProvider同样的效果。

4. 建立异步的数据对象

ObjectDataProvider有IsAsynchronous 可以将数据对象定义为异步的。
默认情况下ObjectDataProvider是同步的,XmlDataProvider是异步。

2. Binding DataContext in Window.DataContext (ObjectDataProvider not needed)

AuctionItem.cs: define Class AuctionItem : INotifyPropertyChanged
MyApp.xaml.cs: define Class AuctionItems : ObservableCollection<AuctionItem>
Window1.xaml.cs: use [CollectionViewSource cv = root.DataContext as CollectionViewSource;] to action in button event handler

Binding Process:

1)Define DataContext in Window1.xaml: 

<Window.DataContext>
    <CollectionViewSource>
      <CollectionViewSource.Source>
        <local:AuctionItems/>

      </CollectionViewSource.Source>
    </CollectionViewSource>
  </Window.DataContext>

2) Binding Listbox:

<ListBox ItemsSource="{Binding Path=.}" IsSynchronizedWithCurrentItem="True">

3) Binding label: (the current item in listbox)

<Label Content="{Binding Path=/}" >

4) DataTemplate

<DataTemplate DataType="{x:Type local:AuctionItem}" >
...
<Image>
       <Image.Source>
                <Binding Path="Image"/>
       </Image.Source>
</Image>
...

More: this sample also shows how to use Converter and MultiBinding

3. Binding DataContext in controls to Global ObjectDataProvider

sample:

MyApp.xaml:

<Application.Resources>
 ...
 <ObjectDataProvider x:Key="Employees" ObjectType="{x:Type local:MSEmployeeCollection}"/>
</Application.Resources>

Window1.xaml:

<StackPanel Margin="10" DataContext="{StaticResource Employees}">
    ...
    <Button Content="{Binding Path=[0]}" />
    <ComboBox ItemsSource="{Binding}" SelectedIndex="0" />
 </StackPanel>

1) DataContext another format : binding to StackPanel
2) Button bind to single item [0]
3) ComblBox bind to multi items, so no Path

II. Binding to XML

1. Use Source include .xml file to XmlDataProvider

<?xml version='1.0' encoding='utf-8'?>
<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Margin="10">
   <StackPanel.Resources>
      <XmlDataProvider x:Key="Blog" Source="http://home.wangjianshuo.com/index.xml"/>
      <DataTemplate x:Key="TitleTemplate">
      <TextBlock Text="{Binding XPath=title}"/>
      </DataTemplate>
      </StackPanel.Resources>
   <Label Content="{Binding Source={StaticResource Blog}, XPath=/rss/channel/title}" FontSize="24" FontWeight="Bold" />
   <Label Content="{Binding Source={StaticResource Blog}, XPath=/rss/channel/description}" FontSize="18" />
   <DockPanel DataContext="{Binding Source={StaticResource Blog}, XPath=/rss/channel/item}" >
 <ListBox DockPanel.Dock="Left" ItemsSource="{Binding}" ItemTemplate="{StaticResource TitleTemplate}" IsSynchronizedWithCurrentItem="True" />
 <TextBox Name="Contents" Text="{Binding XPath=description}" TextWrapping="Wrap" Width="Auto" />
   </DockPanel>
</StackPanel>

2. Use x:XData define the xml structure inside current XmlDataProvider

<StackPanel xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <StackPanel.Resources>
    <XmlDataProvider x:Key="FavoriteColors">
 <x:XData>
  <Colors xmlns="">
   <Color>Blue</Color>
   <Color>Black</Color>
   <Color>Green</Color>
   <Color>Red</Color>
  </Colors>
 </x:XData>
    </XmlDataProvider>
  </StackPanel.Resources>
  <TextBlock HorizontalAlignment="Center"
             FontWeight="Bold">
    XML Example
  </TextBlock>
  <ListBox Width="200" Height="300"
           ItemsSource="{Binding Source={StaticResource FavoriteColors},
           XPath=/Colors/Color}">
  </ListBox>
</StackPanel>

III. Binding to Control

1:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBlock Canvas.Top="25">
      <TextBlock.Text>
        <Binding ElementName="theTextBox" Path="Text" />
      </TextBlock.Text>
    </TextBlock>
  </Canvas>
</Window>

2:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Canvas>
    <TextBox Name="theTextBox" Text="Hello" />
    <TextBlock Canvas.Top="25"
               Text="{Binding ElementName=theTextBox, Path=Text}" />
  </Canvas>
</Window>

IX. Binding to ADO.NET

Similar to binding to object, create a dataset and return ds to DataContext.

 

 

 

 

 

posted @ 2013-09-20 12:01  若愚Shawn  阅读(455)  评论(0编辑  收藏  举报