SilverLight之路(十二)
上一节说了汇总行的模拟实现,效果还不错,但还是有些不完美,比如在表格的最右侧,垂直滚动条的地方就会出现宽度不同步,且两个表格区分太明显,如图
想想实现的原理,就算我们设置了表格的宽度来同步,但垂直滚动条的问题还是解决不了,毕竟是在两个表格中实现的。
想想我们web中的实现,能不能在外面加一个”DIV”呢?以容器的滚动条来代替表格的滚动条,那样又会出现锁行销列的问题,不可行!不过这个方案给我们提供了另外一种思路,既然不能在外面加,那我在里面加不就可以了吗?利用sl强大的控件模板,我们在表格内部加上我们需要的内容,呵呵,这里,就是在gridQuotes表格中把我们的dgSummary表格塞进去。下图是我加完后的结果,可以与原始模板做对比。
在这里,我们可以清楚的看到datagrid的模板组成,发挥想像可以做出各种定制的效果,这就是控件模板的威力。回到我们的项目,我们注意到RowsPresenter这一个元素,它就是我们的主要表格区域,而下面的VerticalScrollbar就是指右侧的垂直滚动条,他们组合在一个grid中,并且位于同一行中,那我们就在原来RowsPresenter的位置入手(注意:上图是我已经加完dgSummary后的结果),加入一个Grid,上下两行,上面是RowsPresenter,下面是我们加入的dgSummary,然后想下我们的布局,与上一节中的反过来了,我们需要设置dgSummary的水平滚动条高度为0(设置不可见的话就不好用了),把gridQuotes的水平滚动条再重新设置出来。我们的ValueChange事件也要反过来,从dgSummary上去掉,加到gridQuotes上。利用上一节介绍的方法来进行相应的修改。
同步列宽:
private DataGrid FindSummaryDataGrid()
{
FrameworkElement fe = this.gridQuotes as FrameworkElement;
DataGrid gd = fe.GetVisualDescendants()
.OfType<DataGrid>()
.Where(s => s.Name == "dgSummary1")
.SingleOrDefault();
return gd;
}
void gridQuotes_LayoutUpdated(object sender, EventArgs e)
{
DataGrid gd = FindSummaryDataGrid();
gd.Columns[0].Width = new DataGridLength(this.gridQuotes.Columns[0].ActualWidth
+ this.gridQuotes.Columns[1].ActualWidth
+ this.gridQuotes.Columns[2].ActualWidth
+ this.gridQuotes.Columns[3].ActualWidth
+ this.gridQuotes.Columns[4].ActualWidth);
for (int i = 1; i < gd.Columns.Count; i++)
{
gd.Columns[i].Width = new DataGridLength(this.gridQuotes.Columns[i + 4].ActualWidth);
}
}
同步水平滚动条
private void HorizontalScrollbar_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<double> e)
{
DataGrid gd = FindSummaryDataGrid();
gd.Scroll(DataGridScrollExtensions.ScrollMode.Horizontal, e.NewValue);
}
因为我们为了加入汇总表格,已经有了自定义的模板,所以可以直接在模板内部给水平滚动条注册事件。
最终,我们的效果如图
至此,行情的主体列表已经基本完成了,接下来看一个简单的详情页,比如我们在行情列表里点击某只基金的名称时,可以在一个新的窗口中显示这只基金的详细信息,比如净值走势,这个页面我没有加太多的信息,主要是想实现一下走势图,如
利用我们第五节中介绍的Chart控件,修改Series类型为LineSeries,然后绑定就行了,没有太大区别,代码如
LineSeries ls = this.chart1.Series[0] as LineSeries;
ls.DependentValueBinding = new System.Windows.Data.Binding("Dwjz");
ls.IndependentValueBinding = new System.Windows.Data.Binding("FSRQ");
ls.ItemsSource = listJZ.Take(100);
不过这里有一个地方要注意,如果按barseries那样,先设置itemsource会报No suitable axis is available for plotting the dependent value.错误。
我们注意到,Chart里面的Series有一个AnimationSequence属性,它可以设置一些动画效果来展示数据,我本想在这里用它实现类似如动态画出曲线的效果,但失败了,网上找到解释说LineSeries不支持Animation,我它的Demo中,我只看到有柱图与饼图有动画效果,其它的都没有见到,不知道是不是只有柱图与饼图才有这个功能。
再介绍一个Tookit中的控件BusyIndicator,它用来显示一个等待窗口,类似之前我们用ChildWindow模拟的效果,但它可以有自己的区域,因为它是一个内容控件,我们可以把需要的控件放到其中,实现效果如
显示全部按钮事件如下
void btnShowAll_Click(object sender, RoutedEventArgs e)
{
this.biWaiting.IsBusy = true;
ThreadPool.QueueUserWorkItem((state) =>
{
Dispatcher.BeginInvoke(() =>
{
LineSeries ls = this.chart1.Series[0] as LineSeries;
ls.ItemsSource = listJZ;
this.biWaiting.IsBusy = false;
});
});
}
关于BusyIndicator的详细用法,请参考Tookit Demo