关于RowFilter的一个过滤控件

[ 2008-01-29 08:16:02 | 作者: admin ]
字号: | |
http://www.cnblogs.com/hushuan/articles/813727.html

开源分享:相当但丰富于DataTable/View数据王国的“BaiDu”超级搜索过滤控件(源码直接贴出来,欢迎转载)

***名称***
淘金筛控件(WebMIS.GoldFilter)源码分享

***用法***
Step1 将淘金筛控件拖至WinForm/WebForm,假如命名为GoldFilter1;
将网格控件拖至WinForm/WebForm,假如命名为DataGrid1;

Step2 在Form_Load/Page_Load事件中过程中,设置DataGrid1的数据源之后,只需指定如下一句一切OK:
GoldFilter1.DataSource = DataGrid1.DataSource

Step3 程序运行时,GoldFilter1自动在WinForm/WebForm中为字段列下拉框加载数据源的各列或指定的列。
为操作类型下拉框加载各种操作,包括各种比较操作如=、<>、>、>=、<、<=、列举多个相等过滤、
两者之间范围比较等及其它的丰富的操作如包含、左包含、右包含模糊匹配。针对常用且实用的
长度判断、空值与非空值过滤特别智能匹配比较等。

***功能特点***
简单快捷、易用实用

***功能描述***
对DataTable/View各列做各种智能匹配、比较操作、模糊匹配查询过滤。
相当但丰富于DataTable/View数据王国的“BaiDu”

***适用范围***
各个网站网页或软件的网格数据过滤,通用于Oracel、SQLServer、ADO.NET的查询过滤。

***操作***
1、智能匹配
字段列下拉框选择一项,操作类型下拉框不用选,直接在过滤输入中输入过滤的数字或文本或日期即可查找过滤。
如果你输入了通配符如%、*号,自动做模糊匹配查找过滤。

2、比较操作
字段列下拉框选择一项,操作类型下拉框选择比较操作,直接在过滤输入中输入过滤的数字或文本或日期即可查找

过滤。
比较操作有如下几种:
相等、不等、大于、大于或等于、小于、小于或等于、两者之间、列举多个(相等)

3、模糊匹配
字段列下拉框选择一项,操作类型下拉框选择包含操作,直接在过滤输入中输入包含的数字或文本或日期即可查找

过滤。
包含操作有如下几种:
包含,过滤所有在过滤输入中的文本中出现的数据
左边象,过滤所有以在过滤输入中的文本开头的数据
右边象,过滤所有以在过滤输入中的文本结尾的数据

ValueTextItem.cs、ValueTextItemCollection.cs两个文件写的类是用来表示加载DataTable/View或网格列。

using System;

namespace WebMIS.GoldFilter
{
/// <summary>
/// 描述键值对,为清晰可见不用KeyValue而用ValueText,均以字符串形式配对,表示值及它的显示文本。
/// </summary>
public class ValueTextItem
{
private string _Value;
private string _Text;

/// <summary>
/// 创建类的新实例
/// </summary>
public ValueTextItem(){}

/// <param name="text">文本值,也就是键名与键值相同</param>
public ValueTextItem(string text):this(text,text)
{

}

/// <param name="val">值,即键名</param>
/// <param name="text">值对应的文本,一般用于显示</param>
public ValueTextItem(string val,string text)
{
_Value = val;
_Text = text;
}

/// <summary>
/// 值,即键名
/// </summary>
public string Value
{
get
{
return _Value;
}
set
{
_Value = value;
}
}

/// <summary>
/// 值对应的文本,一般用于显示
/// </summary>
public string Text
{
get
{
return _Text;
}
set
{
_Text = value;
}
}

/// <summary>
/// 以“值 - 文本”格式返回文本。
/// </summary>
/// <returns></returns>
public override string ToString()
{
return this.Value + " - " + this.Text;
}

}//End Struct

}//End Namespace

using System;
using System.Collections;

namespace WebMIS.GoldFilter
{
/// <summary>
/// 键值对集合
/// </summary>
public class ValueTextItemCollection:CollectionBase
{
public ValueTextItemCollection()
{
//
// TODO: 在此处添加构造函数逻辑
//
}

/// <summary>
/// 将指定的键值对添加到集合的结尾处
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int Add(ValueTextItem item)
{
return this.InnerList.Add(item);
}

/// <summary>
/// 将指定的键值对添加到集合的结尾处
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
public int Add(string val,string text)
{
return this.InnerList.Add(new ValueTextItem(val,text));
}

/// <summary>
/// 获取指定位置的键值对
/// </summary>
public ValueTextItem this[int index]
{
get
{
return this.InnerList[index] as ValueTextItem;
}
set
{
this.InnerList[index] = value;
}
}

/// <summary>
/// 从实例中移除特点的第一个匹配的键值对
/// </summary>
/// <param name="item"></param>
public void Remove(ValueTextItem item)
{
this.InnerList.Remove(item);
}

/*绑定到WinForm和WebForm列表控件

/// <summary>
/// 绑定到列表控件,如ComboBox、ListBox
/// </summary>
/// <param name="listControl">继承于ListControl的列表控件如ComboBox、ListBox</param>
public void BindingTo(System.Windows.Forms.ListControl listControl)
{
listControl.DataSource = this;
listControl.ValueMember = "Value";//ValueTextItem对像的属性名称
listControl.DisplayMember = "Text";
}

/// <summary>
/// 绑定到列表控件,如 CheckBoxList、DropDownList、ListBox 和 RadioButtonList
/// </summary>
/// <param name="listControl">继承于ListControl的列表控件如 CheckBoxList、DropDownList、ListBox 和 RadioButtonList</param>
public void BindingTo(System.Web.UI.WebControls.ListControl listControl)
{
listControl.DataSource = this;
listControl.DataValueField = "Value";
listControl.DataTextField = "Text";
}

*/

}//End Class

}//End Namespace

namespace WebMIS.GoldFilter
{
/// <summary>
/// 过滤操作类型,用于不同场合(Oracle、SqlServer、ADO.NET的RowFilter等)时对应的表达示可能不一样,这里统一定义常用包括比较操作、包含以及其它的操作类型。
/// 但注意如果类型为日期时间型的,如果仅有日期部分则可以完成日期的精确比较;如果带时间,如2005-9-15 00:00:01要完成与2005-9-15的比较,可用Bettween 2005-9-15 And 2005-9-16。
/// </summary>
public enum FilterOperationTypeFlags
{
#region 定义...

/*
/// 例Oracel中日期用to_date函数如Select to_date('字符字段','YYYY-MM-DD') From dual,Select to_char('日期字段','YYYY-MM-DD') From dual,而日期永远没有等于,用大于等于那一天并小于等于下一天即可。
/// SqlServer中用Convert()函数如Select CONVERT(nchar(10), 字段, 120),
/// DataView.RowFilter中用两个#界定日期如"Birthdate < #1/31/82#"(MSDN上是这么说的,其实用'还是可以,可我试了,对Oracel用等号没用,后来解决了,见相GetFilter中程序说明)。
/// 在DataView.RowFilter中数字型字段也可以用Like如rowfilter ="Convert(age, 'System.String') Like '1%'"
/// */

/// <summary>
/// 默认,即 fieldname = 'value',因为Oracle9i、SQLServer2K的数值与字符型及一些字段的SQL和RowFilter支持这种写法。
/// 如果包含了通配符,可以用模糊查询,但是必须转换为字符如rowfilter ="Convert(age, 'System.String') Like '1*'"。
/// </summary>
Default,

/// <summary>
/// 空值,即 fieldname is null,RowFilter="Isnull(fieldname,'Null Column') = 'Null Column'"。
/// </summary>
Null,

/// <summary>
/// 非空值,即 not(fieldname is null),RowFilter="Not(Isnull(fieldname,'Null Column') = 'Null Column')"。
/// </summary>
NotNull,

//******************通用比较******************
#region 定义比较类型包括=、<> 、>、>=、<、<=、Between...And...,In...,同时适用于字符、数字、日期类型。...

/// <summary>
/// 相等,即 fieldname = 'value'。
/// 注意如果类型为日期时间型的,如果仅有日期部分则可以完成日期的精确比较;如果带时间,如2005-9-15 00:00:01要完成与2005-9-15的比较,可用Bettween 2005-9-15 And 2005-9-16。
/// </summary>
Equal,

/// <summary>
/// 不相等,即 fieldname <> 'value'。
/// </summary>
UnEqual,

/// <summary>
/// 大于,即 fieldname > 'value'。
/// </summary>
Great,

/// <summary>
/// 大于等于,即 fieldname >= 'value'。
/// </summary>
GreatEqual,

/// <summary>
/// 小于,即 fieldname < 'value'。
/// </summary>
Little,

/// <summary>
/// 小于等于,即 fieldname <= 'value'。
/// </summary>
LittleEqual,

/// <summary>
/// 介于两值之间,包括两值在内,即 fieldname between 'value1' and 'value2',RowFilter="'value1' <= fieldname And fieldname <= 'value2'"
/// 注意如果类型为日期时间型的,如果仅有日期部分则可以完成日期的精确比较;如果带时间,如2005-9-15 00:00:01要完成与2005-9-15的比较,可用Bettween 2005-9-15 And 2005-9-16。
/// </summary>
BetweenAnd,

/// <summary>
/// 文本在...内,即 fieldname in ('value1','value2',...,'valuen')。
/// </summary>
In,

#endregion

//******************文本包含******************

#region 定义文本包含关系,对应Like关键字,数值、日期型如果转换成文本也可做包含。

/// <summary>
/// 文本包含,即 fieldname Like '%value%'。数值、日期型如果转换成文本也可做包含。。
/// </summary>
TextLike,

/// <summary>
/// 文本左边像,就是以文本开头,左起包含文本,即 fieldname Like 'value%'。数值、日期型如果转换成文本也可做包含。
/// </summary>
TextLeftLike,

/// <summary>
/// 文本右边像,就是以文本结尾,尾边包含文本,即 fieldname Like '%value'。数值、日期型如果转换成文本也可做包含。
/// </summary>
TextLikeRight,

#endregion

/// <summary>
/// 文本长度,即 Oracel\SqlServer\RowFilter分别为Lenght(fieldname) = value、Len(fieldname) = value。
/// </summary>
TextLength,

#endregion
}

/// <summary>
/// 过滤匹配值类型,例如单个比较的相等、Like,两者之间的BetweenAnd和多个的In操作。
/// </summary>
public enum FilterMatchingTypeFlags
{
#region 定义...

/// <summary>
/// 单一值。
/// </summary>
Single,

/// <summary>
/// 用逗号分隔的两个值,用于做介于两值之间的操作。
/// </summary>
BetweenAnd,

/// <summary>
/// 用逗号分隔的多个值,用于做在...内的操作,对应SQL的关键字IN。
/// </summary>
Multi

#endregion
}

/// <summary>
/// 数据过滤,作者:长江支流(周方勇)。下载:www.webmis.com.cn Email:flygoldfish@sina.com QQ:150439795
/// </summary>
public class DataFilter
{
public static string GetFilter(string fieldName,FilterOperationTypeFlags filterOperationType,string filterValue)
{
string strFilter = "";
string strfilterValue = ReplaceSQL(filterValue);

//关于RowFilter的MSDN解释摘录重点几个(其它请参见 DataColumn 类的 Expression 属性):
/*
若要形成 RowFilter 值,请指定列的名称,后跟一个运算符和一个要筛选的值。该值必须用引号括起来。
例如"LastName = 'Smith'"。
若要只返回那些具有空值的列,请使用以下表达式:
"Isnull(Col1,'Null Column') = 'Null Column'"
字符串值应放在单引号内。日期值应放在磅符号 (#) 内(经过试验,无效)。对于数值,允许使用小数和科学记数法。

字符串的开头和结尾处可以使用通配符,%与*等意, 在字符串的中间不允许使用通配符。例如,不允许 'te*xt'。

数据类型总是可以通过检查列的 DataType 属性来确定。还可以使用 Convert 函数来转换数据类型,语法为Convert(expression, dataType)
如"Convert(total, 'System.Int32')"

其它函数支持,如LEN、ISNULL、IIF、TRIM、SUBSTRING
*/

switch(filterOperationType)
{
#region 实现...

case FilterOperationTypeFlags.Default:
//可输入通配符
strFilter = GetStringMatchingFilter(fieldName,strfilterValue);
break;
case FilterOperationTypeFlags.Null:
//strFilter = fieldName + " Is NULL";
strFilter = "Isnull(" + fieldName + ",'Null Column') = 'Null Column'";//这个对空值有效,反而对Int型的无效了
break;
case FilterOperationTypeFlags.NotNull:
//strFilter = "Not(" + fieldName + " Is NULL)";
strFilter = "Not(Isnull(" + fieldName + ",'Null Column') = 'Null Column')";
break;
case FilterOperationTypeFlags.TextLength:
//strFilter = "Length(" + fieldName + ") = " + strfilterValue;//Oracel
//strFilter = "Length(" + fieldName + ") = " + strfilterValue;//SqlServer
strFilter = "Len(" + fieldName + ") = " + strfilterValue;//RowFilter
break;

#region 比较运算,同时适用于字符、数字、日期类型...

case FilterOperationTypeFlags.Equal:
strFilter = fieldName + "='" + strfilterValue + "'";
break;
case FilterOperationTypeFlags.UnEqual:
strFilter = fieldName + "<>'" + strfilterValue + "'";
break;
case FilterOperationTypeFlags.Great:
strFilter = fieldName + ">'" + strfilterValue + "'";
break;
case FilterOperationTypeFlags.GreatEqual:
strFilter = fieldName + ">='" + strfilterValue + "'";
break;
case FilterOperationTypeFlags.Little:
strFilter = fieldName + "<'" + strfilterValue + "'";
break;
case FilterOperationTypeFlags.LittleEqual:
strFilter = fieldName + "<='" + strfilterValue + "'";
break;
case FilterOperationTypeFlags.BetweenAnd:
//用逗号分隔的两个值
strFilter = GetStringMatchingFilter(fieldName,strfilterValue,FilterMatchingTypeFlags.BetweenAnd);
break;
case FilterOperationTypeFlags.In:
//用逗号分隔的多个值
strFilter = GetStringMatchingFilter(fieldName,strfilterValue,FilterMatchingTypeFlags.Multi);
break;

#endregion

#region 定义文本包含关系,对应Like关键字,数值、日期型如果转换成文本也可做包含。

case FilterOperationTypeFlags.TextLike:
strFilter = fieldName + " Like '%" + strfilterValue + "%'";
break;
case FilterOperationTypeFlags.TextLeftLike:
strFilter = fieldName + " Like '" + strfilterValue + "%'";
break;
case FilterOperationTypeFlags.TextLikeRight:
strFilter = fieldName + " Like '%" + strfilterValue + "'";
break;

#endregion

default:
//一般支持加单引号界定
strFilter = fieldName + "='" + strfilterValue + "'";
break;

#endregion
}

return strFilter;
}

/// <summary>
/// 获取数据表或数据视图指定列的过滤字符串,这里根据视图所在的表的指定列自动判断了数值、文本、日期型,如果还有其它的,再完善。
/// 如果列是字符类型,则可以用匹配或模糊(根据是否有通配符)查询;如果是数值型,则完全相等匹配;如果是日期型,查指定日,如带时间,查指定时间及之后的值。
/// </summary>
/// <param name="dataView">数据视图</param>
/// <param name="colName">列名,系统自动根据表中指定的列判断数据类型。</param>
/// <param name="filterValue">过滤值,还可以输入通配符</param>
/// <returns>返回指定列的过滤条件。</returns>
public static string GetFilter(DataView dataView,string colName,string filterValue)
{
return GetFilter(dataView.Table,colName,filterValue);
}

/// <summary>
/// 获取数据表或数据视图指定列的过滤字符串,这里根据表的指定列自动判断了数值、文本、日期型,如果还有其它的,再完善。
/// </summary>
/// <param name="dataTable">数据表</param>
/// <param name="colName">列名</param>
/// <param name="filterValue">过滤值,如果是字符串,还可以输入通配符</param>
/// <returns>返回指定列的过滤条件。</returns>
public static string GetFilter(DataTable dataTable,string colName,string filterValue)
{
#region 实现...

string strFilter = "";
string strfilterValue = ReplaceSQL(filterValue);

System.Type dataType = dataTable.Columns[colName].DataType;
System.TypeCode typeCode = System.Type.GetTypeCode(dataType);

//所以类型可以加引号,但是为了效率,相应的判断一下。

//规则参见RowFilter和DataColumn.Expression属性
//"Isnull(Col1,'Null Column') = 'Null Column'"
//字符串值应放在单引号内。日期值应放在磅符号 (#) 内。对于数值,允许使用小数和科学记数法

//字符串
if(typeCode == System.TypeCode.String)
{
//字符串,用户可以直接输入通配符,通用的是%与_,而Access为*与?
strFilter = GetStringMatchingFilter(colName,strfilterValue);
}
//数值型
else if (typeCode == System.TypeCode.Byte ||
typeCode == System.TypeCode.Char ||
typeCode == System.TypeCode.Decimal ||
typeCode == System.TypeCode.Double ||
typeCode == System.TypeCode.Int16 ||
typeCode == System.TypeCode.Int32 ||
typeCode == System.TypeCode.Int64 ||
typeCode == System.TypeCode.SByte ||
typeCode == System.TypeCode.Single ||
typeCode == System.TypeCode.UInt16 ||
typeCode == System.TypeCode.UInt32 ||
typeCode == System.TypeCode.UInt64)
{
//数值,完全相等,虽然可以加单引号,但是为了提高效率数字相比快。
strFilter = colName + "=" + strfilterValue;
}
else if(typeCode == System.TypeCode.DateTime)
{
//日期,完全相等
/*以下几种不行
strFilter = colName + "='" + strfilterValue + "'";
strFilter = colName + "=#" + strfilterValue + "#";
strFilter = "Convert(" + colName + ",'System.String')='" + strfilterValue + "'";
strFilter = "Convert(" + colName + ",'System.String')=#" + strfilterValue + "#";
strFilter = colName + "=Convert(" + strfilterValue + ",'System.DateTime')";
*/
//strFilter = "Convert(" + colName + ",'System.DateTime')" + "=Convert(" + strfilterValue + ",'System.DateTime')";

/// 例Oracel中日期用to_date函数把字符或字符字段转换成日期(不能转换日期字段本身)如Select to_date('字符字段','YYYY-MM-DD') From dual,
/// 而日期字段本身要格式则用 to_char 如 Select to_char('日期字段','YYYY-MM-DD') From dual,而日期永远没有等于,用大于等于那一天并小于等于下一天即可。
/// SqlServer中用Convert()函数如Select CONVERT(nchar(10), 字段, 120),

try
{
System.DateTime dtStart = System.DateTime.Parse(strfilterValue);
System.DateTime dtEnd = dtStart.AddDays(1);

//MSDN说用#界定,经过运行试验,传统的'还是可以界定。
//主要为了对付Oracel,其它的可以直接用=,Oracel的日期在内核中是用数字表示的,所以他带了时间,根本仅日期比较永远不可能相等。
//strFilter = colName + ">=#" + dtStart.ToString() + "# And " + colName + "<#" + dtEnd.ToString() + "#";//<#改为<=#在Oracel中也只是查dtStart这一天,没有查出下一天,不知其它DB如何,待试。。。
strFilter = colName + ">='" + dtStart.ToString() + "' And " + colName + "<'" + dtEnd.ToString() + "'";
}
catch{}
}
else
{
//其它,完全相等
strFilter = colName + "='" + strfilterValue + "'";
}

return strFilter;

#endregion
}

/// <summary>
/// 将原SQL替换为新的SQL,主要是对一些特殊字符进行处理如一个单引号替换成两个单引号。
/// </summary>
/// <param name="strSQL"></param>
/// <returns></returns>
private static string ReplaceSQL(string sql)
{
string strSql = sql;
strSql = strSql.Replace("'", "''");

return strSql;
}

/// <summary>
/// 智能组合LIKE、=、In或BetweenAnd操作,通用于标准SQL和ADO.NET的RowFilter。
/// 根据是否有通配符决定是完全匹配还是模糊查找,如果用于RowFilter,字符型之外的其它类型可用转换函数Convert执行类字符串的操作如"Convert(age, 'System.String') Like '1%'"。
/// 字符串的开头和结尾处可以使用通配符,%与*等意, 在字符串的中间不允许使用通配符。
/// </summary>
/// <param name="colName">列名</param>
/// <param name="filterValue">过滤值,单值情况下还可以输入通配符(通用的是%与_,而Access为*与?),其它用逗号分隔。</param>
/// <returns></returns>
public static string GetStringMatchingFilter(string colName,string filterValue)
{
return GetStringMatchingFilter(colName,filterValue,FilterMatchingTypeFlags.Single);

}

/// <param name="filterMathcingTypeFlags">过滤值类型,单一值可以用匹配或模糊查询,多个值用In查询,而两者之间的操作用BetweenAnd,非单一值用逗号分隔。</param>
/// <returns></returns>
public static string GetStringMatchingFilter(string colName,string filterValue,FilterMatchingTypeFlags filterMathcingTypeFlags)
{
//智能组合LIKE、=、In或BetweenAnd操作。
#region 实现...

string strFilter = "";

switch(filterMathcingTypeFlags)
{
case FilterMatchingTypeFlags.Single:
//字符串,用户可以直接输入通配符,通用的是%与_,而Access为*与?
if (filterValue.IndexOf('%') > -1 || filterValue.IndexOf('_') > -1 || filterValue.IndexOf('*') > -1 || filterValue.IndexOf('?') > -1)
{
//包含通配符则模糊查询
strFilter = colName + " LIKE '" + filterValue + "'";
}
else
{
//直接相等,以提高效率
strFilter = colName + "='" + filterValue + "'";
}
break;
case FilterMatchingTypeFlags.BetweenAnd:
if(filterValue == null || filterValue == "")
{
strFilter = colName + "=''";
}
else
{
//接受分隔符,或;或-或~
string[] arr = filterValue.Split(',');

if (arr.Length == 1)
{
if (filterValue.IndexOf(';') > -1)
{
arr = filterValue.Split(';');
}
else if (filterValue.IndexOf('-') > -1)
{
arr = filterValue.Split('-');
}
else if (filterValue.IndexOf('~') > -1)
{
arr = filterValue.Split('~');
}
}

if (arr.Length > 1)
{
//在ADO.NET中,经过试验RowFilter不支持Between...And...
//strFilter = colName + " Between '" + arr[0] + "' And '" + arr[1] + "'";

strFilter = colName + ">= '" + arr[0] + "' And " + colName + "<='" + arr[1] + "'";
}
else
{
strFilter = colName + "=''";
}
}
break;
case FilterMatchingTypeFlags.Multi:
if(filterValue == null || filterValue == "")
{
strFilter = colName + "=''";
}
else
{
strFilter = colName + " In (";

//接受分隔符,或;或-或~
string[] arr = filterValue.Split(',');

if (arr.Length == 1)
{
if (filterValue.IndexOf(';') > -1)
{
arr = filterValue.Split(';');
}
}

for(int i = 0 ; i < arr.Length ; i++)
{
strFilter += "'" + arr[i] + "',";
}

//去掉最后一个多余的逗号
strFilter = strFilter.Remove(strFilter.Length -1,1);

strFilter += ")";
}
break;
}

return strFilter;

#endregion 实现...
}

}//End Class
}//End Namespace
评论Feed 评论Feed: http://blog.xg98.com/feed.asp?q=comment&id=1064

这篇日志没有评论。

此日志不可发表评论。