Silverlight学习笔记三:如何自定义DataGrid的Header

接上篇,继续学习DataGrid。下面我来学习DataGrid的Header的自定义功能。
在上篇中,我们实现的对Grid的排序,但是用的是Grid自动生产的Header,现在我们用自定义的控件来代替系统自动生成的Header,并且在Header下面添加一个可以对数据进行过滤的功能。

在这里我参考了silverlight.net上一群牛人的代码。


因为过去没有用过silverlight,在silverlight.net上听说在2.0RC出来之前,自定义ColumnHeader很容易,只需要设置Column.Header为某个控件就可以了,但是现在全变了,Column.Header变成了表头的内容了,要更改Header,必须用做一个新的Style,赋给Column.HeaderStyle。不是太明白微软问什么要这样做,把一个简单的问题搞的很复杂,对一个新手来说,做一个Style真的很费事。按照字面的意思,我认为Style应该是用来控制控件的展现方式,有点像 WEB 上的 CSS ,但是这里的Style不但可以控制如何展示控件,还要设置用什么控件,如何绑定数据,甚至还是事件的处理等等,感觉像个像个自定义控件,但是又没有自定义控件好用。

好了,废话不说了,先看效果:


具体实现的过程:

第一步,我们要做一个新的ColumnHeader。这里直接用来silverlight.net上一位高手的代码,并且做了扩展,主要是添加了Header的点击事件和过滤框的事件,
以及一个新的属性用来保存字段名。应为在实际的项目中,我们不可能在Grid上直接显示数据库的字段名,而是要用中文来显示。代码不是太复杂,就不做解释了。
 GridHeader.cs
ContractedBlock.gif ExpandedBlockStart.gif Code
 1    [TemplatePart(Name = GridHeader.HeaderTextElement, Type = typeof(FrameworkElement))]
 2    [TemplatePart(Name = GridHeader.FilterTextElement, Type = typeof(TextBox))]
 3    public class GridHeader : Control
 4    {
 5    public delegate void HeaderClickEvent(string fieldname);
 6    public event HeaderClickEvent OnSort;
 7 
 8    public delegate void FilterTextEvent(string fieldname, string filtertext);
 9    public event FilterTextEvent OnFilter;
10 
11    protected const string HeaderTextElement = "btnHeaderText";
12    protected const string FilterTextElement = "txtFilerText";
13 
14    Button btn_header;
15    TextBox filterText;
16 
17    #region Constructor
18    public GridHeader()
19    {
20    this.DefaultStyleKey = typeof(GridHeader);
21    }
22    #endregion
23 
24    #region HeaderText
25    /// <summary>
26    /// Identifies the HeaderText dependency property.
27    /// </summary>
28    public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register("HeaderText"typeof(string), typeof(GridHeader), null);
29 
30    /// <summary>
31    /// Gets or sets the HeaderText possible Value of the int object.
32    /// </summary>
33    public string HeaderText
34    {
35    get { return (string)GetValue(HeaderTextProperty); }
36    set { SetValue(HeaderTextProperty, value); }
37    }
38    #endregion HeaderText
39 
40    #region FilterText
41 
42    /// <summary>
43    /// Identifies the FilterText dependency property.
44    /// </summary>
45    public static readonly DependencyProperty FilterTextProperty = DependencyProperty.Register("FilterText"typeof(string), typeof(GridHeader), null);
46 
47    /// <summary>
48    /// Gets or sets the FilterText possible Value of the string object.
49    /// </summary>
50    public string FilterText
51    {
52    get { return (string)GetValue(FilterTextProperty); }
53    set { SetValue(FilterTextProperty, value); }
54    }
55    #endregion FilterText
56 
57    #region FieldText
58    public static DependencyProperty FieldTextProperty = DependencyProperty.Register("FieldText"typeof(string), typeof(GridHeader), null);
59    public string FieldText
60    {
61    get { return (string)GetValue(FieldTextProperty); }
62    set { SetValue(FieldTextProperty, value); }
63    }
64 
65    #endregion
66 
67    public override void OnApplyTemplate()
68    {
69    base.OnApplyTemplate();
70    StackPanel sp = this.GetTemplateChild("LayoutRoot"as StackPanel;
71 
72    btn_header = sp.Children[0as Button;
73    filterText = sp.Children[1as TextBox;
74 
75    if (this.filterText != null)
76    this.filterText.LostFocus += new RoutedEventHandler(filterText_LostFocus);
77    if (this.btn_header != null)
78    this.btn_header.Click += new RoutedEventHandler(header_Click);
79    }
80 
81    void header_Click(object sender, RoutedEventArgs e)
82    {
83    OnSort(FieldText);
84    }
85 
86    void filterText_LostFocus(object sender, RoutedEventArgs e)
87    {
88    OnFilter(FieldText, filterText.Text.Trim());
89    }
90 

第二步,在Themes下添加一个Generic.xaml,内容如下:

 

ContractedBlock.gif ExpandedBlockStart.gif Generic
<ResourceDictionary
   
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:controls
="clr-namespace:SilverlightDemoApp;assembly=SilverlightDemoApp">
   
<Style TargetType="controls:GridHeader">
   
<Setter Property="Template">
   
<Setter.Value>
   
<ControlTemplate TargetType="controls:GridHeader">
   
<StackPanel x:Name="LayoutRoot" Background="{TemplateBinding Background}">
   
<Button x:Name="btnHeaderText" Margin="0" BorderThickness="0" Content="{TemplateBinding HeaderText}"></Button>
   
<TextBox x:Name="txtFilterTextBox" Margin="1,0,1,1" Text="{TemplateBinding FilterText}"/>
   
</StackPanel>
   
</ControlTemplate>
   
</Setter.Value>
   
</Setter>
   
</Style>
 
</ResourceDictionary

这里定义了我们自定义的ColumnHeader的展现方式,包括用了一个Button和TextBox。

关于Generic.xaml我不是太明白这个文件,有些人说会自动产生这个文件,但是我的机器上并没有这个文件,我是手工添加的,现建一个themes下建一个 SilverLight用户控件,然后用上面的内容替换掉自动生成的内容,并且去掉Generic.xaml.cs的public Generic()里面的代码。

第三步,在DataGrid页面上添加Resources。如下:
 
ContractedBlock.gif ExpandedBlockStart.gif Code
 <UserControl.Resources>
   
<Style x:Key="grid-header" TargetType="primitives:DataGridColumnHeader">
   
<Setter Property="VerticalAlignment" Value="Center" />
   
<Setter Property="HorizontalAlignment" Value="Stretch" />
   
<Setter Property="Template">
   
<Setter.Value>
   
<ControlTemplate>
   
<my:GridHeader HeaderText="{TemplateBinding Content}" Height="Auto" Loaded="GridHeader_Loaded" />
   
</ControlTemplate>
   
</Setter.Value>
   
</Setter>
   
</Style>
   
</UserControl.Resources

注意,要在文件头部加上
xmlns:my="clr-namespace:SilverlightDemoApp;assembly=SilverlightDemoApp"
就是这个my:GridHeader的namespace和assembly信息。不然就找不到my:GridHeader的了。

第四步,实现DataGrid所在页面的代码。

基础的代码可以见我的前一篇文档。

Silverlight学习笔记二:DataGrid 服务器端分页、排序的实现

Silverlight学习笔记二(续)

这里主要写一下修改的地方
xaml中的DataGrid部分。

 

ContractedBlock.gif ExpandedBlockStart.gif Code
  <!--DataGrid-->
   
<data:DataGrid x:Name="dgData" AutoGenerateColumns="False"
   SelectionMode
="Single" IsReadOnly="True"
   Grid.Column
="0" Grid.Row="2"
   Height
="Auto" Width="Auto" CanUserSortColumns="False"
   CanUserReorderColumns
="False"
   MouseEnter
="dgData_MouseEnter" MouseLeave="dgData_MouseLeave"
   
>
   
<data:DataGrid.Columns>
   
<data:DataGridTextColumn Header="产品编号" Binding="{Binding ProductID}"></data:DataGridTextColumn>
   
<data:DataGridTextColumn Header="产品名称" Binding="{Binding ProductName}"></data:DataGridTextColumn>
   
<data:DataGridTextColumn Header="单价" Binding="{Binding UnitPrice}"></data:DataGridTextColumn>
   
<data:DataGridTextColumn Header="库存数量" Binding="{Binding UnitsInStock}"></data:DataGridTextColumn>
   
<data:DataGridTextColumn Header="订单数量" Binding="{Binding UnitsOnOrder}"></data:DataGridTextColumn>
   
<data:DataGridTextColumn Header="规格" Binding="{Binding QuantityPerUnit}"></data:DataGridTextColumn>
   
<data:DataGridCheckBoxColumn Header="是否停产" Binding="{Binding Discontinued}"></data:DataGridCheckBoxColumn>
   
<data:DataGridTemplateColumn Header="操作">
   
<data:DataGridTemplateColumn.CellTemplate>
   
<DataTemplate>
   
<StackPanel Orientation="Horizontal">
   
<Button x:Name="btnEdit" Content="编辑" ></Button>
   
<Button x:Name="btnDelete" Content="删除"></Button>
   
</StackPanel>
   
</DataTemplate>
   
</data:DataGridTemplateColumn.CellTemplate>
   
</data:DataGridTemplateColumn>
   
</data:DataGrid.Columns>
   
</data:DataGrid>

在获取数据之后,对DataGrid的Header进行了处理。新增了CreateHeader()这个方法。

 

 1     private   void  client_GetProductsPagingCompleted( object  sender, GetProductsPagingCompletedEventArgs e)
 2     {
 3      if  (e.Error  ==   null )
 4     {
 5     products_list  =  e.Result.ToList();
 6     dgData.ItemsSource  =  products_list;
 7      if  (pager  ==   null )
 8     {
 9     pager  =   new  Pager(e.TotalPage,  2 );
10     pager.Click  +=   new  Pager.PagerButtonClick(pager_Click);
11     pager.PageIndex  =   1 ;
12     spPager.Children.Clear();
13     spPager.Children.Add(pager);
14      // 第一次时创建GridHeader
15     CreateHeader();
16     }
17     }
18      else
19     MessageBox.Show(e.Error.Message);
20     canvas.Visibility  =  Visibility.Collapsed;
21     }
22 
23     // 用来存储HeaderText和数据库字段之间的对照信息
24     Dictionary < string string >  FieldDict  =   new  Dictionary < string string > ();
25      private   void  CreateHeader()
26     {
27     var v  =  from p  in  dgData.Columns
28      where  p  is  DataGridBoundColumn
29     select p;
30      foreach  (DataGridBoundColumn column  in  v.ToList())
31     {
32      string  fieldname  =  column.Binding.Path.Path;
33     Style style_header  =  Resources[ " grid-header " as  Style;
34     column.HeaderStyle  =  style_header;
35 
36      // 本来这里我是希望可以直接设置Header的FieldText为字段名的,但是却找不到什么好的方法,
37      //
38      // <my:GridHeader HeaderText="{TemplateBinding Content}" Height="Auto" Loaded="GridHeader_Loaded" />
39      // Resources中这里也不能直接绑定FieldText为Binding.Path.Path,因为这里是从DataGridColumnHeader来的,
40      // DataGridColumnHeader只有Content,而找不到对应的绑定信息。
41      //
42      // 另外,通过访问Style的Setter,我也只能获取到ControlTemplate,但是ControlTemplate下面的内容,也就是my:GridHeader取怎么也获取不到,
43      // 如果有高人知道,请指教一下。谢谢
44      //
45      // 所以,没办法,只能暂时把字段名和HeaderText都保存到Dictionary里面,供后面使用
46 
47     FieldDict.Add(column.Header.ToString(), fieldname);
48     }
49     }
50 
51      private   void  GridHeader_Loaded( object  sender, RoutedEventArgs e)
52     {
53     GridHeader header  =  sender  as  GridHeader;
54     header.OnFilter  +=   new  GridHeader.FilterTextEvent(header_OnFilter);
55     header.OnSort  +=   new  GridHeader.HeaderClickEvent(header_OnSort);
56      string  fieldtext;
57      // 在这里,我们对Header的FieldText设置为字段名。
58      // 如果能在这里获取到当前的Column的话,前面就不要用Dictionary了,但是这里我仍然不知道该怎么获取到当前的Column。
59      if  (FieldDict.TryGetValue(header.HeaderText,  out  fieldtext))
60     header.FieldText  =  fieldtext;
61     }
62 
63      void  header_OnSort( string  fieldname)
64     {
65      // 这里具体的代码就不写了。
66      // 在获取到字段名之后,对数据进行排序。
67     MessageBox.Show( " 对字段: "   +  fieldname  +   " 进行排序 " );
68     }
69 
70      void  header_OnFilter( string  fieldname,  string  filtertext)
71     {
72      // 这里具体的代码就不写了。
73      // 在获取到字段名和关键字只有,就可以通过WCF获取到指定的数据了。
74     MessageBox.Show( " 对字段: "   +  fieldname  +   "  按照  "   +  filtertext  +   "  进行过滤 " );
75     }

ok,打完手工。


转载于:https://www.cnblogs.com/libra163/archive/2008/12/29/1364453.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值