关于基金行情,经过第九节中的设置,现在已经可以锁定列头了,而设置了ForzenColumnCount属性后,也可以锁定行头,这在基本的应用中已经够了,但我们这个要求除锁定的行头以后,还有两行需要锁定,就是最下面的“上证”与“平均”,看下图
初看上去,好像是合并列的需求,我开始时也是这么想的,于是网上找了好久,最终也没有找到一个合适的方案,倒是找到了一些关于合并列头的方法,可是那个在我们这个需求中没有用。
我又想到了RowStyle与DetailsTemplete实现,但它们的行为也与我们的需求不符,虽然可以做一些控制来模拟,但毕竟都是“猪鼻子插大葱----装像”罢了,于是我们还要继续想想办法。
One day later…
我用了两个表格来实现, gridQuotes中是正常的各基金数据,dgSummary只有两行“平均”、“上证”;数据分类与绑定很好解决,问题是,如何同步两个表格的各列宽度呢?继续try,最终方案是在gridQuotes表格的LayoutUpdated事件中进行处理,代码如
void gridQuotes_LayoutUpdated(object sender, EventArgs e)
{
for (int i = 1; i < this.dgSummary.Columns.Count; i++)
{
this.dgSummary.Columns[i].Width = new DataGridLength(this.gridQuotes.Columns[i + 4].ActualWidth);
}
}
因为我们的dgSummary表格中前5列是要合并的,就是说dgSummary表格中第一列的列宽要与gridQuotes表格中的前五列保持同步,那么我们在for循环外部设置就可以了(HardCode,不好!)
this.dgSummary.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);
现在运行起来看看,列宽已经可以同步了,但现在两个表格各自都有自己的水平滚动条(我这个需求中列数比较多,如果列数少,也就不需要水平滚动了),且分别影响两个表格,那我们的下一个问题,就是要解决水平滚动条同步了。
这个问题也不好解决,继续google吧(这里推荐使用google,虽然它经常会访问不了,但毕竟sl的中文资源太少,baidu在这方面就显得太苍白了),中间的各种try我就不说了,直接说结果
我们知道,datagrid控件的属性中,并没有哪个地方可以访问得到滚动条的,但当我们进行模板编辑中却可以在模版中发现有滚动条的存在,那我们就可以在自定义模板时给dgSummary的滚动条加上Scroll事件(后面使用的是ValueChange事件),如果不想自定义模板,也可以使用VisualTreeHelper来辅助帮忙查找,如
private ScrollBar GetScrollbar(DependencyObject dpObj, string name)
{
for (var i = 0; i < VisualTreeHelper.GetChildrenCount(dpObj); i++)
{
var child = VisualTreeHelper.GetChild(dpObj, i);
ScrollBar scrollBar = child as ScrollBar;
if (scrollBar != null && scrollBar.Name == name)
{
return scrollBar;
}
else
{
scrollBar = GetScrollbar(child, name);
if (scrollBar != null)
{
return scrollBar;
}
}
}
return null;
}
我们也可以用Linq来更“优美”的实现同样的目的
private ScrollBar GetScrollbar(DependencyObject dpObj, string name)
{
FrameworkElement fe = dpObj as FrameworkElement ;
return fe.GetVisualDescendants()
.OfType<ScrollBar>()
.Where(s => s.Orientation == Orientation.Horizontal)
.SingleOrDefault();
}
找到需要的滚动条后,就可以给它注册Scroll事件了
scroll = GetScrollbar(this.dgSummary, "HorizontalScrollbar");
scroll.Scroll += new ScrollEventHandler(scroll_Scroll);
然后我们期望以此来做了滚动条同步
void scroll_Scroll(object sender, ScrollEventArgs e)
{
ScrollBar scroll1 = GetScrollbar(this.gridQuotes, "HorizontalScrollbar");
if (scroll1 != null)
{
scroll1.SetValue(ScrollBar.ValueProperty, e.NewValue);
}
}
结果呢,滚动条确实同步了,但内容没发生滚动,擦。。。。。。
这是肿么了?哪里出问题了呢?这里发现一个小问题,当第一次滚动时,上面的滚动条没有跟着变,于是我们把Scroll改成ValueChange事件,这个小问题就是解决了,但还是只是滚动条在动,内容不动啊。
没招了,我继续Google,于是找到了一个辅助类DataGridScrollExtensions,看它的实现,区别有两处,获取目标滚动条时,它是这样实现的
private static IScrollProvider GetScrollProvider(DataGrid grid)
{
var p = FrameworkElementAutomationPeer.FromElement(grid) ?? FrameworkElementAutomationPeer.CreatePeerForElement(grid);
return p.GetPattern(PatternInterface.Scroll) as IScrollProvider;
}
然后设置目标滚动位置时调用SetScrollPercent方法
switch (mode)
{
case ScrollMode.Vertical:
scrollProvider.SetScrollPercent(System.Windows.Automation.ScrollPatternIdentifiers.NoScroll, percent);
break;
case ScrollMode.Horizontal:
scrollProvider.SetScrollPercent(percent, System.Windows.Automation.ScrollPatternIdentifiers.NoScroll);
break;
}
行不行,我们试下就知道了,改造我们原来的代码
void scroll_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
{
this.gridQuotes.Scroll(DataGridScrollExtensions.ScrollMode.Horizontal, this.dgSummary.GetScrollPosition(DataGridScrollExtensions.ScrollMode.Horizontal));
//ScrollBar scroll1 = GetScrollbar(this.gridQuotes, "HorizontalScrollbar");
//if (scroll1 != null)
//{
// scroll1.SetValue(ScrollBar.ValueProperty, e.NewValue);
//}
}
真的可以了~!
其中的原因,有哪位高人能给解释一下吗,我没太搞清楚。
最后,还有一点小瑕疵,上面的表格的滚动条应该去掉才对,于是我想当然的设置了它不可见,惨,滚动条不好用了!看来设置了它不可见,似乎也同时去掉了它本身,这样不行,那我们就用模板来设置吧,把它的Height设置为0,瞒天过海,ok了,呵呵。