首页 > 娱乐 > 来一个邪恶的RP测试工具(下)

来一个邪恶的RP测试工具(下)

2009年1月6日

在上一篇日志里,我实现了一个简单的RP测试工具,接下来,我需要完善它:将名字输入栏修改成下拉框形式:存储最新输入的十个名字:

修改布局

添加一个ToggleButton:

image

<ToggleButton HorizontalContentAlignment="Right" Grid.Column="1"
              Height="25" HorizontalAlignment="Right" VerticalAlignment="Center"
              Width="20" x:Name="RPToogleButton">
    <Path Height="4" HorizontalAlignment="Center" Margin="0,0,4,0" x:Name="BtnArrow"
          Width="8" Stretch="Uniform" VerticalAlignment="Center"
          Data="F1 M 301.14,-189.041L 311.57,-189.041L 306.355,-182.942L 301.14,-189.041 Z ">
        <Path.Fill>
            <SolidColorBrush Color="#FF333333" x:Name="BtnArrowColor"/>
        </Path.Fill>
    </Path>
</ToggleButton>

插入Popup控件,设置Popup位置如图,在Popup控件上添加一个ListBox控件,并调整其大小:

image我们需要将ToggleButton的IsChecked和Popup控件的IsOpen绑定在一起。

添加绑定

和WPF不同,Silverlight不支持UI元素间的互相绑定。因此,需要添加一个“绑定帮助对象”数据源,ToolButton的IsChecked属性和Popup的IsOpen属性分别双向绑定到该数据源上,来实现联动效果:

image

public class BindingHelper : INotifyPropertyChanged
{
    protected bool isToggleChecked = false;

    public bool IsToggleChecked
    {
        get { return isToggleChecked; }
        set
        {
            if (isToggleChecked!=value)
            {
                isToggleChecked = value;
            }

            OnPropertyChanged("IsToggleChecked");
        }
    }

    private void OnPropertyChanged(string p)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(p));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
}

在Popup控件的IsOpen属性中,选择数据绑定:

image

在创建数据绑定对话框中点击添加CLR对象按钮,选择数据源类型:

image

点击确定,回到创建数据绑定对话框,选中刚才添加的数据源,在绑定方向中选择TwoWay:

image对ToolButton的IsChecked做同样的操作:

<Popup IsOpen="{Binding Mode=TwoWay, Path=IsToggleChecked,
    Source={StaticResource BindingHelperDS}}">
<ToggleButton IsChecked="{Binding Mode=TwoWay, Path=IsToggleChecked,
    Source={StaticResource BindingHelperDS}}">

添加数据源

接下来为ListBox添加数据源,当点击ToggleButton时,在弹出的ListBox中显示最新测试过的10个人的RP值。

由于需要双向通信,我选择ObservableCollection<T>作为数据源,在后台代码中添加代码如下:

public class RPValue
{
    public String Name { get; set; }
    public int rp { get; set; }
}

public class RPCollection : ObservableCollection<RPValue>
{
}

使用RPCollection而不直接使用ObservableCollection的原因是,Silverlight的XAML里不支持直接使用泛型对象,而通过继承,我们就可以在Expression Bland的添加CLR对象数据源对话框中直接找到RPCollection这个类:

image

把ListBox的ItemsSource绑定到新添加的数据源,将绑定方向设置为双向,然后点击数据模板按钮。

image image由于在Expression Bland2生成的数据模板中 ,StackPanel是垂直排列的,因此需要修改一下,可以在资源里面选中添加的模板,然后在设计器里修改:

image 也可以直接修改XAML文件:

<DataTemplate x:Key="RPCollectionTemplate">
    <StackPanel Orientation="Horizontal">
        <TextBlock Text="{Binding Path=Name}" Width="80" FontSize="12"/>
        <TextBlock Text="{Binding Path=rp}" FontSize="12" Foreground="#FFFF0000"/>
    </StackPanel>
</DataTemplate>

响应选择操作

为了方便操作,我添加了两个get属性来获取数据源对象:

public RPCollection RPs
{
    get
    {
        return Resources["RPCollectionDS"] as RPCollection;
    }
}
public BindingHelper bind
{
    get
    {
        return Resources["BindingHelperDS"] as BindingHelper;
    }
}

添加ListBox的SelectionChanged事件处理方法:当ListBox中某一项被选中时,用选中的项替换TextBox的名字,并关闭ListBox:

private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    var lb = sender as ListBox;

    if (lb.SelectedItem != null)
    {
        NameTextBox.Text = (lb.SelectedItem as RPValue).Name;
    }

    bind.IsToggleChecked = false;
}

保存输入的名字和结果

在RPCollection中添加一个InsertItem方法,用来插入结果最新的计算结果:

public void InsertItem(RPValue value)
{
    if (this.SingleOrDefault(x => x.Name == value.Name) == null)
    {
        if (this.Count == 10)
        {
            RemoveAt(9);
        }
        InsertItem(0, value);
    }
}

将结果保存到计算机

和Flex一样,Silverlight提供了独立存储技术(IsolatedStorage),用来在宿主计算机中保存一定量的数据,即使在是浏览器关闭的情况下,保存的数据依然存在。

首先把RPCollection转换成String:

public String ToText()
{
    String text = String.Empty;

    foreach (var v in this)
    {
        text += (v.Name + "," + v.rp.ToString() + "|");
    }
    return text.Substring(text.Length - 1);
}

public void FromText(String text)
{
    Clear();
    foreach (var t1 in text.Split('|'))
    {
        var t2=t1.Split(',');
        Add(new RPValue() { Name = t2[0], rp = int.Parse(t2[1]) });
    }
}

分别在构造函数里添加读取独立存储文件的过程和在每次添加Item的时候保存文件的过程,

读取存储文件

public RPCollection()
{
    if (store.FileExists(fname))
    {
        using (IsolatedStorageFileStream isfs =
            new IsolatedStorageFileStream(fname, FileMode.OpenOrCreate, store))
        {
            using (StreamReader streamReader = new StreamReader(isfs))
            {
                FromText(streamReader.ReadLine());
            }
        }
    }
}

保存文件

public void InsertItem(RPValue value)
{
    if (this.SingleOrDefault(x => x.Name == value.Name) == null)
    {
        if (this.Count == 10)
        {
            RemoveAt(9);
        }
        InsertItem(0, value);

        if (store.FileExists(fname))
        {
            store.DeleteFile(fname);
        }

        using (IsolatedStorageFileStream isfs =
            new IsolatedStorageFileStream(fname, FileMode.OpenOrCreate, store))
        {
            using (StreamWriter streamWriter = new StreamWriter(isfs))
            {
                streamWriter.WriteLine(ToText());
                streamWriter.Flush();
            }
        }
    }
}

参考文献及源码下载

Silverlight vs Flash: Local Storage

Silverlight 2.0 beta1 and WPF Data Binding – what’s the same and what’s different?

源代码在这里下载

snowwaft 娱乐

  1. 目前还没有任何评论.
  1. 目前还没有任何 trackbacks 和 pingbacks.
您必须在 登录 后才能发布评论.