标签: DataGrid

  • 项目总结-wpf 使用经验

    刚做完一个使用了wpf技术的项目,总结一下项目中使用到的一些以前没用过的技术

    DataGrid 过滤

    nuget库 DataGridExtensions 提供了自定义扩展DataGrid列过滤的方法

    根据例子中的MultipleChoiceFilter 可以自定义任意过滤。

    我的日期过滤控件:

     // xaml: 
     <Control x:Class= "readLog.Views.Filters.DateFilter" 
              x:Name= "Control" 
                  xmlns= "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
                  xmlns:x= "http://schemas.microsoft.com/winfx/2006/xaml" 
                  xmlns:mc= "http://schemas.openxmlformats.org/markup-compatibility/2006" 
                  xmlns:d= "http://schemas.microsoft.com/expression/blend/2008" 
                  xmlns:local= "clr-namespace:readLog.Views.Filters" 
                  xmlns:dgx= "urn:tom-englert.de/DataGridExtensions" 
                  xmlns:sys= "clr-namespace:System;assembly=mscorlib" 
                  mc:Ignorable= "d" 
                  d:DesignHeight= "30"  d:DesignWidth= "30" 
              >
     
         <Control.Resources>
     
             <ObjectDataProvider x:Key= "dateTypeEnum"  MethodName= "GetValues" 
                                 ObjectType= "{x:Type sys:Enum}" >
     
                 <ObjectDataProvider.MethodParameters>
     
                     <x:Type TypeName= "local:DateFilterType" ></x:Type>
     
                 </ObjectDataProvider.MethodParameters>
     
             </ObjectDataProvider>
     
         </Control.Resources>
     
         <Control.Template>
     
             <ControlTemplate>
     
                 <Grid>
     
                     <ToggleButton x:Name= "ToggleButton" >
     
                         <StackPanel Orientation= "Horizontal" >
     
                             <TextBlock x:Name= "IsFilterActiveMarker"  Text= "."  Margin= "0,0,-4,0"  Foreground= "{Binding ElementName=FilterSymbol, Path=Foreground}"  FontWeight= "Bold"  />
     
                             <Control x:Name= "FilterSymbol"  Style= "{DynamicResource {x:Static dgx:DataGridFilter.IconStyleKey}}"  />
     
                         </StackPanel>
     
                     </ToggleButton>
     
                     <Popup 
     
                         DataContext= "{Binding ElementName=Control}" 
                            x:Name= "Popup"  IsOpen= "{Binding Path=IsChecked, ElementName=ToggleButton, Mode=TwoWay}" 
                            AllowsTransparency= "True"  StaysOpen= "False" >
     
                         <StackPanel>
     
                             <ComboBox x:Name= "typeBox" 
                                       ItemsSource= "{Binding Source={StaticResource dateTypeEnum}}" 
                                       SelectedItem= "{Binding Path=FilterType}" />
     
     
     
                             <DatePicker x:Name= "begTm" 
                                         Visibility= "{Binding Path=BeginTimeVisible}" 
                                         SelectedDate= "{Binding Path=BeginTime}" 
                                         />
     
                             <DatePicker x:Name= "endTm" 
                                         Visibility= "{Binding Path=EndTimeVisible}" 
                                         SelectedDate= "{Binding Path=EndTime}" 
                             />
     
     
     
                         </StackPanel>
     
                     </Popup>
     
                 </Grid>
     
             </ControlTemplate>
     
         </Control.Template>
     
     </Control>
     
     
    
    
     // 交互 
     /// <summary> 
     ///  DateFilter.xaml 的交互逻辑 
     /// </summary> 
     public partial class DateFilter  :  Control 
         {
     
     public DateFilter ( ) 
     {
     
                 InitializeComponent();
     
             }
     
     
     
     # region  dependency property 
     
     
     public static readonly  DependencyProperty FilterTypeProperty = DependencyProperty.Register(
     
     "FilterType" ,  typeof (DateFilterType),  typeof (DateFilter), 
     
     new  FrameworkPropertyMetadata( default (DateFilterType), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => ((DateFilter)s).FilterTypeChange()));
     
     
     
     
     
     private void FilterTypeChange ( ) 
     {
     
     // 可见性 
     switch  (FilterType)
     
                 {
     
     case  DateFilterType.All:
     
     case  DateFilterType.ThisYear:
     
     case  DateFilterType.ThisMonth:
     
     case  DateFilterType.PreYear:
     
     case  DateFilterType.PreMonth:
     
                         BeginTimeVisible = Visibility.Collapsed;
     
                         EndTimeVisible = Visibility.Collapsed;
     
     break ;
     
     case  DateFilterType.Earlier:
     
                         BeginTimeVisible = Visibility.Collapsed;
     
                         EndTimeVisible = Visibility.Visible;
     
     break ;
     
     case  DateFilterType.Later:
     
                         BeginTimeVisible = Visibility.Visible;
     
                         EndTimeVisible = Visibility.Collapsed;
     
     break ;
     
     case  DateFilterType.Between:
     
                         BeginTimeVisible = Visibility.Visible;
     
                         EndTimeVisible = Visibility.Visible;
     
     break ;
     
     default :
     
     throw new  ArgumentOutOfRangeException();
     
                 }
     
     
     
                 RangeChanged();
     
             }
     
     
     
     private void RangeChanged ( ) 
     {
     
                 Filter =  new  ContentFilter(FilterType, BeginTime, EndTime);
     
             }
     
     
     
     
     
     public  DateFilterType FilterType
     
             {
     
     get  => (DateFilterType) GetValue(FilterTypeProperty);
     
     set  => SetValue(FilterTypeProperty,  value );
     
             }
     
     
     
     public static readonly  DependencyProperty FilterProperty = DependencyProperty.Register(
     
     "Filter" ,  typeof (ContentFilter),  typeof (DateFilter), 
     
     new  FrameworkPropertyMetadata( default (ContentFilter), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => ((DateFilter)s).FilterChanged()));
     
     
     
     public  ContentFilter Filter
     
             {
     
     get  => (ContentFilter) GetValue(FilterProperty);
     
     set  => SetValue(FilterProperty,  value );
     
             }
     
     
     
     private void FilterChanged ( ) 
     {
     
     var  filter = Filter  as  ContentFilter;
     
     if  ( null  == filter)
     
                 {
     
     return ;
     
                 }
     
     
     
                 FilterType = filter.FilterType;
     
                 BeginTime = filter.BeginTime;
     
                 EndTime = filter.EndTime;
     
             }
     
     
     
     public static readonly  DependencyProperty BeginTimeProperty = DependencyProperty.Register(
     
     "BeginTime" ,  typeof (DateTime),  typeof (DateFilter),
     
     new  FrameworkPropertyMetadata(DateTime.Today, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,(s, e) => ((DateFilter)s).RangeChanged()));
     
     
     
     public  DateTime BeginTime
     
             {
     
     get  => (DateTime) GetValue(BeginTimeProperty);
     
     set  => SetValue(BeginTimeProperty,  value );
     
             }
     
     
     
     public static readonly  DependencyProperty EndTimeProperty = DependencyProperty.Register(
     
     "EndTime" ,  typeof (DateTime),  typeof (DateFilter),
     
     new  FrameworkPropertyMetadata(DateTime.Today, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,(s, e) => ((DateFilter)s).RangeChanged()));
     
     
     
     public  DateTime EndTime
     
             {
     
     get  => (DateTime) GetValue(EndTimeProperty);
     
     set  => SetValue(EndTimeProperty,  value );
     
             }
     
     
     
     public static readonly  DependencyProperty PropertyTypeProperty = DependencyProperty.Register(
     
     "BeginTimeVisible" ,  typeof (Visibility),  typeof (DateFilter),
     
     new  FrameworkPropertyMetadata(Visibility.Collapsed, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => ((DateFilter)s).RangeChanged()));
     
     
     
     public  Visibility BeginTimeVisible
     
             {
     
     get  => (Visibility) GetValue(PropertyTypeProperty);
     
     set  => SetValue(PropertyTypeProperty,  value );
     
             }
     
     
     
     public static readonly  DependencyProperty EndTimeVisibleProperty = DependencyProperty.Register(
     
     "EndTimeVisible" ,  typeof (Visibility),  typeof (DateFilter), 
     
     new  FrameworkPropertyMetadata(Visibility.Collapsed, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, (s, e) => ((DateFilter)s).RangeChanged()));
     
     
     
     public  Visibility EndTimeVisible
     
             {
     
     get  => (Visibility) GetValue(EndTimeVisibleProperty);
     
     set  => SetValue(EndTimeVisibleProperty,  value );
     
             }
     
     
     
     
     
     
     
     # endregion 
     
     
     public class ContentFilter  :  IContentFilter 
             {
     
     public ContentFilter ( DateFilterType type, DateTime beg, DateTime end ) 
     {
     
                     FilterType = type;
     
                     BeginTime = beg;
     
                     EndTime = end;
     
                 }
     
     
     
     public bool IsMatch ( object value ) 
     {
     
     if  ( null  ==  value )
     
                     {
     
     return false ;
     
                     }
     
     
     
     try 
                     {
     
     var  tm = (DateTime)  value ;
     
     
     
     switch  (FilterType)
     
                         {
     
     case  DateFilterType.All:
     
     return true ;
     
     case  DateFilterType.ThisYear:
     
     return  IsMatchYear(tm, DateTime.Today);
     
     case  DateFilterType.ThisMonth:
     
     return  IsMatchMonth(tm, DateTime.Today);
     
     case  DateFilterType.PreYear:
     
     return  IsMatchYear(tm, DateTime.Today.AddYears( -1 ));
     
     case  DateFilterType.PreMonth:
     
     return  IsMatchMonth(tm, DateTime.Today.AddMonths( -1 ));
     
     case  DateFilterType.Earlier:
     
     return  tm.Date <= EndTime.Date;
     
     case  DateFilterType.Later:
     
     return  tm.Date >= BeginTime.Date;
     
     case  DateFilterType.Between:
     
     return  IsMatchDate(tm, BeginTime, EndTime);
     
     default :
     
     throw new  ArgumentOutOfRangeException();
     
                         }
     
                     }
     
     catch  (Exception e)
     
                     {
     
     return false ;
     
                     }
     
     
     
                 }
     
     
     
     
     
     public  DateFilterType FilterType {  get ; }
     
     
     
     public  DateTime BeginTime {  get ; }
     
     
     
     public  DateTime EndTime {  get ; }
     
     
     
     # region  Datetime 
     private bool IsMatchMonth ( DateTime tm, DateTime toMatch ) 
     {
     
     return  IsMatchDate(tm, GetFirstDayOfMonth(toMatch), GetLastDayOfMonth(toMatch));
     
                 }
     
     
     
     private bool IsMatchDate ( DateTime tm, DateTime beg, DateTime end ) 
     {
     
                     tm = tm.Date;
     
     return  tm <= beg && tm >= end;
     
                 }
     
     
     
     private bool IsMatchYear ( DateTime tm, DateTime toMatch ) 
     {
     
     return  IsMatchDate(tm, GetLastDayOfYear(toMatch), GetFirstDayOfYear(toMatch));
     
                 }
     
     
     
     private  DateTime  GetFirstDayOfMonth ( DateTime dt ) 
     {
     
     var  dtFrom = dt;
     
                     dtFrom = dtFrom.AddDays(-(dtFrom.Day -  1 ));
     
     
     
     return  dtFrom;
     
                 }
     
     
     
     private  DateTime  GetLastDayOfMonth ( DateTime dt ) 
     {
     
     var  dtTo = dt;
     
                     dtTo = dtTo.AddMonths( 1 );
     
                     dtTo = dtTo.AddDays(-(dtTo.Day));
     
     return  dtTo;
     
                 }
     
     
     
     private  DateTime  GetFirstDayOfYear ( DateTime dt ) 
     {
     
     var  dtFrom = dt;
     
                     dtFrom = dtFrom.AddMonths(-(dtFrom.Month -  1 ));
     
     return  GetFirstDayOfMonth(dtFrom);
     
                 }
     
     
     
     private  DateTime  GetLastDayOfYear ( DateTime dt ) 
     {
     
     var  dtTo = dt;
     
                     dtTo = dtTo.AddYears( 1 );
     
                     dtTo = dtTo.AddMonths(-dt.Month);
     
     
     
     return  GetLastDayOfMonth(dtTo);
     
                 }
     
     
     
     
     
     # endregion 
             }
     
         }
     
     
     
         [TypeConverter( typeof (EnumDescriptionTypeConverter))]
     
     public enum  DateFilterType
     
         {
     
             [Description( "所有" )]
     
             All,  // 全部 
             [Description( "今年" )]
     
             ThisYear,
     
             [Description( "本月" )]
     
             ThisMonth,
     
             [Description( "去年" )]
     
             PreYear,
     
             [Description( "上个月" )]
     
             PreMonth,
     
             [Description( "指定日期以前" )]
     
             Earlier,
     
             [Description( "指定日期以后" )]
     
             Later,
     
             [Description( "之间" )]
     
             Between,
     
     
     
     
     
         }
     
     
    
    

    枚举显示

    枚举显示有两个方案,

    1. 转换器, 在xaml中定义一个转换器资源
    2. 定义一个用来显示的字符串属性,界面绑定这个字符串属性。

    读取DataGrid某一行某一列的值

    从控件 DataGridExtensions 中学习到的。拿到的是真实的绑定对象,而不是显示的字符串。一开始用 GetCelllContent(),但对未显示的行无法取到。

     class GetCellValueClass  :  DependencyObject 
             {
     
     /// <summary> 
     ///  Identifies the CellValue dependency property, a private helper property used to evaluate the property path for the list items. 
     /// </summary> 
     private static readonly  DependencyProperty _cellValueProperty =
     
                     DependencyProperty.Register( "_cellValue" ,  typeof ( object ),  typeof (GetCellValueClass));
     
     
     
     public object GetCellValue ( DataGridColumn col,  object  item ) 
     {
     
     var  propertyPath = col.SortMemberPath;
     
     if  ( string .IsNullOrEmpty(propertyPath))
     
     return null ;
     
     
     
                     BindingOperations.SetBinding( this , _cellValueProperty,  new  Binding(propertyPath) { Source = item });
     
     var  propertyValue = GetValue(_cellValueProperty);
     
                     BindingOperations.ClearBinding( this , _cellValueProperty);
     
     
     
     return  propertyValue;
     
                 }
     
     
     
     
     
             }
     
     
    
    

    使用方法:

     new  GetCellValueClass().GetCellValue(col, item);