彩票走势图

ListView点击列头排序功能的实现

转帖|其它|编辑:郝浩|2011-07-27 15:13:36.000|阅读 908 次

概述:这是一个非常常见的功能,要求也很简单,在Column Header上显示一个小三角表示表示现在是在哪个Header上的正序还是倒序就可以了。微软的MSDN也已经提供了实现方式。微软的方法中,是通过 ColumnHeader Template实现的,一共要维护至少两个Header Template,一个显示正三角,一个显示倒三角。在用户点击Header的时候同时切换使用的Template。如果你的ListView只提供 Sort功能,这个方法就可以了。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

  这是一个非常常见的功能,要求也很简单,在Column Header上显示一个小三角表示表示现在是在哪个Header上的正序还是倒序就可以了。微软的MSDN也已经提供了实现方式。微软的方法中,是通过ColumnHeader Template实现的,一共要维护至少两个Header Template,一个显示正三角,一个显示倒三角。在用户点击Header的时候同时切换使用的Template。如果你的ListView只提供Sort功能,这个方法就可以了。但是如果你的ListView还在在Header中提供Filter功能呢?如果还需要用户可以配置是否开启Sort和Filter功能呢?那么你就需要6个Template来处理Sort和Filter的组合。如果在Header本来就有好几种(文字Header、画片Header等)或是要放入更多的功能呢?显然微软的这个方式只能用于技术演示(当然MSDN本来就是这个目的),面对实际项目时就会力不从心。Google搜索WPF ListView Sort,可以找到很多不同的实现方式。

  1. SwitchOnTheCode:使用Adorner Layer,重写Adorner的OnRender方法,画出一个三角形。画个三角可以,要画个有发光、渐变、动画效果的三角,代码会变得很难维护。而且不能用Blend去编辑这个样式。不过思路是很好的,因为它不会占用控件的现有的任何属性,就不会有微软的方式中功能组合的问题。

  2. Jeol Rumerman’s Blog:继承GridViewColumn,扩展出Sort功能。还是用Header Template,更糟糕的是,为加一个功能而使用继承本身就不是一个很好的设计。同理要加个Filter功能,是不是还要继承出一个FilteredGridViewColumn和FilteredAndSortedGridViewColumn呢?不仅要处理Template的组合,还会产生类膨胀,实在是不可取。

  3. CodeProject WPFListViewSorter:与微软的方式一样,只是通过自定义Sorter函数解决了微软的方式中,把Column Header上的名字,当作Sort Property的问题。

  4. Thejoyofcode:通过Attached Property解决了同样的问题,而且没有界面显示的实现。而且还继承出了一个SortableListView。缺点就不再解释了。

  5. Marlongrech:提供了Disable/Enable  Sort功能。不过也是用HeaderTemplate做界面实现。(突然发现Wordpress可以访问了)

  没有找到一个满足我要求的实现方式,每个解决方案都只是关注于自己要解决的问题的那一个点上。当然在Blog里让示例简单一些也没有错。那就让我把他们所解决的问题集成到一个示例中。要求也不多。

  1. 不影响现有功能。

  2. 不独占现有属性。

  3. 使用组合,而不是继承。

  第一个方案,使用Adorner Layer是个很好的思路,Adorner Layer相当于一个画板,我画在这里,别的功能画在那里就是了,所以不会影响现有功能也不算独占现有属性。它的示例中占用了Tag来描述使用哪个属性排序。我们用Attached Property替换掉就可以了。然后就剩下一个问题了——不要画三角。我们想用Template。这样不同的地方的样子可以有不一样的界面效果而又不用修改代码。但是问题是Adorner是没有Template的。

  参考了两篇关于Adorner Layer的文章。

  1. Adorners in WPF

  2. Visual Level Programming vs Logical Level Programming

  写了一个晚上的代码,终于搞出一个自我感觉良好的实现出来。在ListView上添加Sort功能,只需要添加一个Attached Property就可以。代码如下。

<ListView ext:ListViewBehavior.HeaderSort="True"
       ItemsSource="{Binding}">
     <ListView.View>
       <GridView>
         <GridViewColumn Header="Name"
             DisplayMemberBinding= "{Binding ItemName}"
             ext:ListViewBehavior.SortField= "ItemName"/>
         <GridViewColumn Header="Value"
             DisplayMemberBinding= "{Binding ItemValue}"
             ext:ListViewBehavior.SortField= "ItemValue"/>
       </GridView>
     </ListView.View>
</ListView>

  在GridViewColumn中也使用Attached Property指定按哪一列排序。如果不指定,就默认使用Header的名称做为排序属性。

  使用了Sheva的示例中的UIElementAdorner(略有改动)把一个自定义控件ListSortDecorator放在当前排序列上。代码如下。

using System.Collections;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media;

namespace SortListView.Extention
{
     public class UIElementAdorner : Adorner
     {
         private UIElement child;

         ///  <summary>
         /// 
         ///  </summary>
         ///  <param name="element"></param>
         ///  <param name="direction"></param>
         public UIElementAdorner(UIElement element, UIElement child)
             : base(element)
         {
             this.child = child;
             AddLogicalChild(child);
             AddVisualChild(child);
         }

         protected override Size ArrangeOverride(Size finalSize)
         {
             child.Arrange(new Rect(finalSize));

             return finalSize;
         }

         protected override Size MeasureOverride(Size constraint)
         {
             child.Measure(constraint);

             return AdornedElement.RenderSize;
         }

         protected override int VisualChildrenCount
         {
             get { return 1; }
         }

         protected override Visual GetVisualChild(int index)
         {
             return child;
         }

         protected override IEnumerator LogicalChildren
         {
             get
             {
                 ArrayList list = new ArrayList();
                 list.Add(child);
                 return (IEnumerator)list.GetEnumerator();
             }
         }

         ///  <summary>
         /// 
         ///  </summary>
         public UIElement Child
         {
             get { return child; }
         }
     }
}

  三角形的样子就可以由ListSortDecorator来定义了。默认的样子如下。

<ControlTemplate TargetType="{x:Type ext:ListSortDecorator}">
   <Path x:Name="path" Data="M0,0L2,0 1,1z"
       Fill= "{TemplateBinding Foreground}"
       Stroke= "{TemplateBinding Foreground}"
       HorizontalAlignment= "{TemplateBinding HorizontalContentAlignment}"
       VerticalAlignment= "{TemplateBinding VerticalContentAlignment}"
       Width= "7" Height="4" Stretch="Fill"/>
   <ControlTemplate.Triggers>
     <Trigger Property="SortDirection" Value="Descending">
       <Setter TargetName="path" Property="Data" Value="M0,1L2,1L1,0Z"/>
     </Trigger>
   </ControlTemplate.Triggers>
</ControlTemplate>

  这样就可以方便地在Blend中绘制三角形的样子并制作动画了。显示效果如图所示。


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:网络转载

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP