第11課 數據綁定

本文爲系列文章第十一篇,主要介紹Silverlight 2中的數據綁定。

數據綁定模式

在Silverlight 2中,支持三種模式的數據綁定。

1.OneTime:一次綁定,在綁定創建時使用源數據更新目標,適用於只顯示數據而不進行數據的更新。

2.OneWay:單向綁定,在綁定創建時或者源數據發生變化時更新到目標,適用於顯示變化的數據。

3.TwoWay:雙向綁定,在任何時候都可以同時更新源數據和目標。

Jesse Liberty舉的例子非常的形象,使用Silverlight開發一個在線書店,顯示書籍的書名、作者等信息,使用OneTime模式,這些數據一般不會發生變化的;顯示價格信息時使用OneWay模式,因爲管理員可能會在一天內調整價格;顯示書籍的剩餘數量時用TwoWay模式,數量隨着用戶的訂購會隨時發生變化,即目標和源數據都要進行更新。

簡單數據綁定

在本示例中我們將做一個簡單的數據綁定,用來顯示用戶信息,XAML如下:

<Grid x:Name="LayoutRoot" Background="#46461F">
    <Grid.RowDefinitions>
        <RowDefinition Height="160"></RowDefinition>
        <RowDefinition Height="40"></RowDefinition>
        <RowDefinition Height="40"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Image Source="terrylee.jpg" Width="78" Height="100"
           HorizontalAlignment="Left" Grid.Row="0" Grid.Column="1"/>
    <TextBlock Foreground="White" FontSize="18" Text="姓名:"
               Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right"/>
    <TextBlock x:Name="lblName" Foreground="White" FontSize="18"
               Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"/>
    <TextBlock Foreground="White" FontSize="18" Text="位置:"
               Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right"/>
    <TextBlock x:Name="lblAddress" Foreground="White" FontSize="18"
               Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"/>
</Grid>

添加一個簡單User類,它具有Name和Address兩個屬性:

public class User
{
    public string Name { get; set; }

    public string Address { get; set; }
}

使用綁定句法{Binding Property}進行數據綁定,注意下面的兩個TextBlock控件Text屬性:

<Grid x:Name="LayoutRoot" Background="#46461F">
    <Grid.RowDefinitions>
        <RowDefinition Height="160"></RowDefinition>
        <RowDefinition Height="40"></RowDefinition>
        <RowDefinition Height="40"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Image Source="terrylee.jpg" Width="78" Height="100"
       HorizontalAlignment="Left" Grid.Row="0" Grid.Column="1"/>
    <TextBlock Foreground="White" FontSize="18" Text="姓名:"
           Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right"/>
    <TextBlock x:Name="lblName" Foreground="White" FontSize="18"
               Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
               Text="{Binding Name}"/>
    <TextBlock Foreground="White" FontSize="18" Text="位置:"
               Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right"/>
    <TextBlock x:Name="lblAddress" Foreground="White" FontSize="18"
               Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"
               Text="{Binding Address}"/>
</Grid>

指定數據源,注意這裏是創建一個User的實例並賦值後,把user實例綁定到了TextBlock的DataContext上,而不是向之前我們所做的示例中那樣,直接指定Text屬性:

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    User user = new User();
    user.Name = "TerryLee";
    user.Address = "中國 天津";

    lblName.DataContext = user;
    lblAddress.DataContext = user;
}

運行示例後,可以看到:

TerryLee_Silverlight2_0055

上面這種數據綁定模式,只是顯示數據而不對數據做任何修改,默認的綁定模式是一次綁定OneTime。

單向綁定示例

如果需要在數據源發生變化時能夠通知UI進行相應的更新,即使用單向綁定OneWay或者雙向綁定TwoWay,則業務實體需要實現接口INotifyPropertyChanged。在本示例中,我們加上一個更新按鈕,當單擊按鈕時更新user實例的屬性值,會看到界面上的數據也會發生變化。

修改一下User類,使其實現INotifyPropertyChanged接口。

public class User : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    private string _name;
    public string Name
    {
        get { return _name; }
        set 
        {
            _name = value;
            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
            }
        }
    }

    private string _address;
    public string Address
    {
        get { return _address; }
        set 
        {
            _address = value;
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs("Address"));
            }
        }
    }
}

修改數據綁定模式,使用單向綁定OneWay模式,如{Binding Address, Mode=OneWay}

<Grid x:Name="LayoutRoot" Background="#46461F">
    <Grid.RowDefinitions>
        <RowDefinition Height="160"></RowDefinition>
        <RowDefinition Height="40"></RowDefinition>
        <RowDefinition Height="40"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="150"></ColumnDefinition>
        <ColumnDefinition Width="*"></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Image Source="terrylee.jpg" Width="78" Height="100"
       HorizontalAlignment="Left" Grid.Row="0" Grid.Column="1"/>
    <Button x:Name="btnUpdate" Width="100" Height="40"
            Content="Update" Click="btnUpdate_Click"/>
    <TextBlock Foreground="White" FontSize="18" Text="姓名:"
           Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right"/>
    <TextBlock x:Name="lblName" Foreground="White" FontSize="18"
               Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left"
               Text="{Binding Name, Mode=OneWay}"/>
    <TextBlock Foreground="White" FontSize="18" Text="位置:"
               Grid.Row="2" Grid.Column="0" HorizontalAlignment="Right"/>
    <TextBlock x:Name="lblAddress" Foreground="White" FontSize="18"
               Grid.Row="2" Grid.Column="1" HorizontalAlignment="Left"
               Text="{Binding Address, Mode=OneWay}"/>
</Grid>

編寫事件處理程序,爲了演示把user聲明爲一個全局的,並在按鈕的單擊事件中修改其屬性值:

public partial class Page : UserControl
{
    public Page()
    {
        InitializeComponent();
    }
    User user;
    private void UserControl_Loaded(object sender, RoutedEventArgs e)
    {
        user = new User();
        user.Name = "TerryLee";
        user.Address = "中國 天津";

        lblName.DataContext = user;
        lblAddress.DataContext = user;
    }

    private void btnUpdate_Click(object sender, RoutedEventArgs e)
    {
        user.Name = "李會軍";
        user.Address = "China Tianjin";
    }
}

運行後如下所示:

TerryLee_Silverlight2_0056

單擊Update按鈕後:

TerryLee_Silverlight2_0057

綁定到列表

下面再看一個綁定到列表的簡單例子,一般都會使用DataGrid或者ListBox來進行列表數據的顯示。下面的示例我們顯示一個文章列表:

<Grid Background="#46461F">
    <Grid.RowDefinitions>
        <RowDefinition Height="40"></RowDefinition>
        <RowDefinition Height="*"></RowDefinition>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition></ColumnDefinition>
    </Grid.ColumnDefinitions>
    <Border Grid.Row="0" Grid.Column="0" CornerRadius="15"
            Width="240" Height="36" Background="Orange"
            Margin="20 0 0 0" HorizontalAlignment="Left">
        <TextBlock Text="文章列表" Foreground="White"
                   HorizontalAlignment="Left" VerticalAlignment="Center"
                   Margin="20 0 0 0"></TextBlock>
    </Border>
    <ListBox x:Name="PostList" Grid.Column="0" Grid.Row="1"
             Margin="40 10 10 10"
             HorizontalContentAlignment="Left" VerticalContentAlignment="Bottom"
             ItemsSource="{Binding Posts}">
    </ListBox>
</Grid>

編寫一個簡單的業務類:

public class Blog
{
    public List<String> Posts { get; set; }
}

初始化集合數據並進行綁定

private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    Blog blog = new Blog();
    blog.Posts = new List<String>
    {
        "一步一步學Silverlight 2系列(10):使用用戶控件",
        "一步一步學Silverlight 2系列(9):使用控件模板",
        "一步一步學Silverlight 2系列(8):使用樣式封裝控件觀感",
        "一步一步學Silverlight 2系列(7):全屏模式支持"
    };

    PostList.DataContext = blog;
}

最終運行的結果如下所示:

TerryLee_Silverlight2_0058

當然我們也可以使用ListBox的ItemsSource屬性進行綁定,

結束語

本文簡單介紹了Silverlight 2中的數據綁定,你可以從這裏下載文章示例代碼。