案例分析Silverlight中的Binding技术

在WPF(Windows Presentation Foundation)中,提供了数据的binding技术,使显示和交互数据变得简单,并与数据的管理独立。Data binding可以同步两个不同对象的两个属性值。例如,我们需要在界面上显示一个内容动态变化的文本框,我们可以建立一个binding对象,把文本框的值和一个变量绑定,这样每次修改这个变量或者修改文本框的值时,另一端的内容就可以自动同步。在Silverlight中,由于XAML这种标记语言的运用,使得binding变得更加简单了。只需要用简短的一个属性值就可以定义一个binding。

为了更形象一点,我们还是用一个例子来深入binding技术。假设现在在联网游戏对战平台中,需要一个文本标签,显示我方的人数。此外还有一个列表,显示一个服务器上的所有在线玩家。大体界面如下图所示:

image

现在我们假设游戏后台有一个Game类,其中包含了我方人数、在线玩家的信息,这些数据由其他模块提供。我们需要将它们独立于数据管理部分显示出来。

先看看我方玩家数目的显示,为简化问题,假设Game类中有一个整型变量:

public int TeammateCount;

存储了表示我方人数的字符串。为了实现binding,首先必须让Game类继承INotifyPropertyChanged接口,此接口提供了PropertyChanged事件。

public class Game : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    // Bla bla bla
}

接下来,需要在TeammateCount的值发生改变的时候,触发这一事件。因此要改变TeammateCount属性set方法的行为:

private int _TeammateCount;
public int TeammateCount
{
    get { return _TeammateCount; }
    set
    {
        _TeammateCount = value;
        NotifyPropertyChanged("TeammateCount");
    }
}

public void NotifyPropertyChanged(string propertyName)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this,
            new PropertyChangedEventArgs(propertyName));
    }
}

上面的工作是为了使binding的源的值发生改变时,能及时发出事件,通知binding对象。如果binding的源所在的类是UIElement的子类,这个工作也可以交给DependencyProperty来完成。

下面就很简单了,只需要在XAML中加上相关的binding,并在C#代码中指定DataContent即可。

<sdk:Label Name="lblTeammateCount"
           Content="{Binding TeammateCount}" />
 
Game game = new Game();

public MainPage()
{
    InitializeComponent();
    lblTeammateCount.DataContext = game;
}

在Test按钮中加一小段代码测试一下

private void btnTest_Click(object sender, RoutedEventArgs e)
{
    game.TeammateCount = 123;
}

点击按钮之后,发现显示的结果立刻发生了变化,我们的第一个小实验圆满结束。

image

下面我们来增加问题的难度,更深入地学习binding。假设现在我们并不是直接输出人数的阿拉伯数字形式,而是逐位转换成汉字呢?这时,就需要借助binding的数据转换(Data Conversions)了。为了实现转换,我们需要定义一个继承IValueConverter接口的类 NumberConverter:

public class NumberConverter : IValueConverter
{
    static String zhNum = "〇一二三四五六七八九";
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        String s = "";
        foreach (Char c in value.ToString())
            if (c >= '0' && c <= '9')
                s += zhNum[c - '0'];
        return s;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

然后,再界面的XAML中加入相应实现binding  converter的代码:

<UserControl.Resources>
    <local:NumberConverter x:Key="numberConverter" />
</UserControl.Resources>
<sdk:Label Name="lblTeammateCount"
            Content="{Binding TeammateCount, Converter={StaticResource numberConverter}}" />

如此即可实现带有数据转换的binding。

image

作为最后一个例子,我们来看看如何把Listbox的内容binding到一个Collection。Silverlight中已经实现了一个ObservableCollection类,继承了INotifyCollectionChanged接口,当Collection的内容发生改变时,自动触发CollectionChanged事件。因此,我们不需要像上面一样专门写一个类,直接使用现成的就可以了。

首先,需要定义玩家的数据类型:

public class Player
{
    public int ID { get; set; }
    public String Name { get; set; }

    public Player(int id, String name)
    {
        ID = id;
        Name = name;
    }
}

注意这里必须要为成员定义public的get方法,否则binding会失败。

接下来,在Game类中添加Players成员:

public ObservableCollection<Player> Players;

修改界面中ListBox的定义:

<ListBox Name="lstPlayers">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding ID}" />
                <TextBlock Text="," />
                <TextBlock Text="{Binding Name}" />
            </StackPanel>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

这里定义了ListBox中每个Item的显示方式,bind到什么路径的信息。

然后在主界面的构造函数中添加:

lstPlayers.ItemsSource = game.Players;

指定ListBox的数据源。如此即可完成整个Collection的binding过程,当Players发生改变时,界面显示也会改变。

image

 

菜鸟初学Silverlight,还望高手多多指教! 

转载于:https://www.cnblogs.com/OMG-Team/archive/2011/09/06/2169119.html

猜你喜欢

转载自blog.csdn.net/weixin_34041003/article/details/93758935