如何实现Silverlight DataGrid控件的列宽自动填充

在WinForm中,将DataGridView控件的列的AutoSizeMode属性设置为Fill,然后将FillWeight属性设置为列宽所占的权重,这样可实现列宽自动填充列,下图说明自动填充宽度的算法:

1

但是在Silverlight中,DataGrid控件的列宽只有四种模式:Auto、Pixel、SizeToCells、SizeToHeader,没有Fill模式,无法实现自动填充列宽。

那怎么实现此功能呢?用自定义模板?似乎比较麻烦,并且很难实现重用。看来只有用自定义控件了,先初步分析,首先,我们要控制列宽,肯定得处理DataGrid的SizeChanged事件;其次,我们必须定义DataGrid中每列宽度的填充模式;最后,还得定义每列宽度所占的权重。后两个步骤如何实现呢?Silverlight DataGrid控件中的列有三种类型DataGridTextColumn、DataGridCheckBoxColumn以及DataGridTemplateColumn,如果我们再分别为这三种类型创建子类来添加自定义属性显然太麻烦。

DataGrid需要知道每个DataGridColumn中的宽度模式及填充比例,以便在DataGrid SizeChanged事件中设置每列的宽度,但是我们又要避免重新去定义每个DataGridColumn类型。Silverlight已经为此中问题提供了一种设计模式:即附加属性。我们常用的Grid布局控件,其中Grid.Row及Grid.Column属性即为附加属性,添加到Grid中的控件并没有Row和Column属性,但是通过Grid的Row和Column附加属性即可通知Grid控件应该被放到哪行哪列。同理,我们为DataGrid添加一个附加属性,即可让DataGrid中的每一列向DataGrid说明该列的填充模式和宽度所占的权重。为了简便,我们添加一个附加属性:WidthWeight,int类型,如果为0表示该列为固定宽度,否则表示该列所占权重。

关于附加属性,请参考Silverlight SDK文档,有中文版本,简单易学:)

贴代码:

隐藏行号 复制代码 AutoFillDataGrid.cs
  1. using System;
    
  2. using System.Net;
    
  3. using System.Windows;
    
  4. using System.Windows.Controls;
    
  5. using System.Windows.Documents;
    
  6. using System.Windows.Ink;
    
  7. using System.Windows.Input;
    
  8. using System.Windows.Media;
    
  9. using System.Windows.Media.Animation;
    
  10. using System.Windows.Shapes;
    
  11. using System.Collections.Generic;
    
  12. 
    
  13. namespace Test
    
  14. {
    
  15.     public class AutoFillDataGrid : DataGrid
    
  16.     {
    
  17.         public static readonly DependencyProperty WidthWeightProperty = DependencyProperty.RegisterAttached(
    
  18.             "WidthWeight", typeof(int), typeof(AutoFillDataGrid), new PropertyMetadata(0));
    
  19.         private double paddingRight = 0;
    
  20. 
    
  21.         public AutoFillDataGrid()
    
  22.         {
    
  23.             this.SizeChanged += new SizeChangedEventHandler(AutoFillDataGrid_SizeChanged);
    
  24. 
    
  25.         }
    
  26. 
    
  27.         void AutoFillDataGrid_SizeChanged(object sender, SizeChangedEventArgs e)
    
  28.         {
    
  29.             int weight = 0;
    
  30.             double fix = 0;
    
  31.             int temp = 0;
    
  32.             Queue<DataGridColumn> queue = new Queue<DataGridColumn>();
    
  33. 
    
  34.             foreach (DataGridColumn column in this.Columns)
    
  35.             {
    
  36.                 temp = (int)column.GetValue(WidthWeightProperty);
    
  37.                 if (temp > 0)
    
  38.                 {
    
  39.                     weight += temp;
    
  40.                     queue.Enqueue(column);
    
  41.                 }
    
  42.                 else
    
  43.                 {
    
  44.                     fix += column.ActualWidth;
    
  45.                 }
    
  46.             }
    
  47. 
    
  48.             double width = e.NewSize.Width - this.paddingRight - fix - this.Padding.Left - this.Padding.Right;
    
  49.             double actualWidth = 0;
    
  50.            
    
  51.             while (queue.Count > 0)
    
  52.             {
    
  53.                 DataGridColumn column = queue.Dequeue();
    
  54.                 temp = (int)column.GetValue(WidthWeightProperty);
    
  55.                 actualWidth = width * (double)temp / weight;
    
  56.                 if (actualWidth < column.MinWidth)
    
  57.                 {
    
  58.                     actualWidth = column.MinWidth;
    
  59.                 }
    
  60.                 if (actualWidth > column.MaxWidth)
    
  61.                 {
    
  62.                     actualWidth = column.MaxWidth;
    
  63.                 }
    
  64.                 column.Width = new DataGridLength(actualWidth);
    
  65. 
    
  66.             }
    
  67.         }
    
  68. 
    
  69.         /// <summary>
    
  70.         /// 右ò边?间?距à,?可é看′着?为aDataGrid的?滚?动ˉ条?宽í度è
    
  71.         /// </summary>
    
  72.         public double PaddingRight
    
  73.         {
    
  74.             get
    
  75.             {
    
  76.                 return this.paddingRight;
    
  77.             }
    
  78.             set
    
  79.             {
    
  80.                 this.paddingRight = value;
    
  81.             }
    
  82.         }
    
  83. 
    
  84.         public static void SetWidthWeight(DataGridColumn column, int value)
    
  85.         {
    
  86.             column.SetValue(WidthWeightProperty, value);
    
  87.         }
    
  88. 
    
  89.         public static int GetWidthWeight(DataGridColumn column)
    
  90.         {
    
  91.             return (int)column.GetValue(WidthWeightProperty);
    
  92.         }
    
  93.     }
    
  94. }
    
  95. 
    
  96. 
    

 

OK,我们已经实现自己的DataGrid控件,下一步就是如何使用了:

最简单的办法,在Silverlight项目上单击右键,选择生成,完成后,打开我们的xaml文件,此时工具箱中会出现我们的AutoFillDataGrid控件,拖动到xaml文件中即可。然后就像使用DataGrid控件一样,向AutoFillDataGrid中添加列,关键点是在需要自动填充列宽的DataGridColumn上设置AutoFillDataGrid.WidthWeight属性。

示例源码下载 <---Visual 2010,如果使用Visual 2008请自己创建新工程,然后粘贴代码

posted @ 2010-09-25 14:46  xfrog  阅读(5306)  评论(4编辑  收藏  举报