DataGrid in Silverlight - Row Recycling

在Silverlight 2期间,我主要参与了DataGrid的开发测试,在这里主要集中谈以下几个大家容易遇到的问题。

首先要谈到的就是DataGrid Row的Recycle/Reuse问题。

为了提高DataGrid的Performance, DataGrid 的行 (DataGridRow) 是虚拟的,不是和数据一一对应的,即采取了Row Recycling 和 Reusing. 当一个DataGrid建立的时候,只有能显示区域的Row Instances被创建,当用户进行上下滚动时,滚动出显示区域的Row instance会被重新用于显示新“滚动进”显示区域的Entity.在这里如果一切都是通过DataBinding进行的,那基本不会出现问题。但如果用户动态改变了某些行的属性,而不是通过DataBinding,那就会有一些问题了。因为DataGrid是不会主动更改这些用户Dynamic设置的属性的。所以用户看到的情形就是当滚动的时候,DataGrid变成很混乱的状态。这里用户需要负责更新这些被动态更改了的属性。

举个例子:

DataGridRow 唯一可以访问的途径就是通过 LoadingRow event Args, 所以很多人希望通过这里有条件的改变行的一些属性, 比如:

        void dg_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            if (e.Row.GetIndex() % 2 == 0)
                e.Row.Background = new SolidColorBrush(Colors.Yellow);           
        }

 需要注意的是这里直接改变的是DataGridRow的属性,而这个属性和数据是不相关的。所以当页面刚Load的时候,我们看到的是期望的效果:

但是,当用户开始上下滚动的时候,就会发现,行似乎随机的背景都慢慢变成设置的颜色:

这里的问题就是已经改变了属性的行滚动出显示区域以后,会马上被重新绑定到新的Object上,并从另一端显示出来,这个过程中,此行所有没有绑定的属性是不会改变的。上例中的BackGround就没有改变,所以我们看到慢慢的所有的行都改变了颜色。

避免这个问题有两种方法:

  1. 使用Binding. 比如把这个行的属性同该行所包含的object的某个属性绑定起来,这样,DataGrid load新行的时候就会自动更新该属性。
  2. 手动更新.比如上例中,我们在LoadingRow event handler中改变了该属性,那我们就要把每次该行load的时候都手工的更改此属性,如:

        void dg_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            if (e.Row.GetIndex() % 2 == 0)
                e.Row.Background = new SolidColorBrush(Colors.Yellow);
            else
                e.Row.Background = new SolidColorBrush(Colors.White);
        }

dg1.JPG