Winforms平台界面开发技巧,如何快速掌握Filter Editor(一)

a 夏天 提交于 2020-03-13 13:45:59

下载DevExpress v19.2完整版

DevExpress Winforms Controls 内置140多个UI控件和库,完美构建流畅、美观且易于使用的应用程序。想要体验?点击下载>>

DevExpress WinForms安装附带两个允许最终用户构建过滤器查询的控件:提供GUI的Filter控件和将Filter控件与基于文本输入的面板组合在一起的Filter Editor控件。WinForms中,大多数数据感知控件都使用这些组件,但是您也可以将其包含在自己的表单中,并根据需要将其绑定到数据感知控件中。

为了说明这一点,下面是带有Filter Editor的数据网格,用户可以单击过滤器面板中的Edit Filter按钮来调出Filter Editor,并且由于属性DefaultFilterEditorView设置为TextAndVisual,因此可以看到Filter Editor Control的文本面板。

在下图中,您可以看到两个控件中可用的一些标准功能,包括“小于或等于”,“大于或等于”,“今天”,“昨天”以及许多其他功能。Filter控件和Filter Editor控件均提供多种功能供您选择,可用功能集因要为其构建表达式的数据字段的类型而异。

自定义函数

在某些情况下,标准函数集还不够。技术团队在处理大量技术支持问题发现,查找是最常见需要的自定义函数。以下是三种最受欢迎的方案:

  • 标准函数的倒置,可以在filter editor中手动应用这些,但是对于频繁使用,自定义函数更方便。
  • 表示复杂表达式的标准函数组合的函数。 例如,Within Days of X函数可能包含行,其中字段值在给定日期之前或之后的N天内,这省去了用户在两个不同日期之间配置标准函数的工作量。
  • 自定义DateTime函数,例如Is Weekend,N Days Ago等。

从v19.1开始,Filter Editor控件和Filter控件完全支持自定义函数,从而可以轻松实现上述方案和许多其他方案。

技术基础

自定义函数是实现接口ICustomFunctionDisplayAttributes的类,请注意如果需要服务器端对自定义函数的处理,则可以额外实现ICustomFunctionOperatorFormattable接口,但是在本文范围内,我们仅关注ICustomFunctionDisplayAttributes。

这些是接口实现所需的方法和属性:

  • Name - 您用来从代码中引用自定义函数的技术功能名称
  • DisplayName - GUI中显示的可读函数名称。 例如,名称为NotStartsWith的函数的DisplayName可能不是开头的
  • Image - Filter Control菜单中为该函数显示的图标,该属性类型为Object,但是下面的示例显示了如何使用现有的标准图像,也可以分配图像对象
  • Description - 用户在Filter Editor控件的文本面板中编辑表达式时,在弹出提示中的函数描述
  • Category - Expression Editor的函数类别,如果您打算仅将函数用于过滤器,则这无关紧要
  • MinOperatorCount, MaxOperatorCount, IsValidOperandCount - 该函数支持运算符数量,对于Filter和Filter Editor控件,所有三个值可以相等。 如果计划在Expression Editor中使用函数,则可以灵活地支持可变数量的运算符。
  • IsValidOperandType - 调用每个操作数来检查是否具有有效的类型,仅检查第一个操作数的筛选器
  • ResultType - 函数的返回值类型,Filter控件仅显示具有布尔结果类型的函数
  • Evaluate - 该函数在函数每次对一个数据字段求值时都会调用的方法,值在操作数数组中传递。 返回true包括相关行,返回false排除相关行。

最后,我们建议添加两个静态便利函数Register和Unregister。 这是一个可选步骤,但是实现很简单(请参见下文),并且它们以CriteriaOperator类型调用现有的帮助器。

示例

供您参考,下面是三个示例,它们涵盖了上面提到的三个最需要的方案。 第一个自定义函数称为NotBeginsWith,它是对标准函数BeginsWith的取反。

public class NotBeginsWithFunction : ICustomFunctionDisplayAttributes {
public const string FunctionName = "NotBeginsWith";
static readonly NotBeginsWithFunction instance = new NotBeginsWithFunction();
public static void Register() {
CriteriaOperator.RegisterCustomFunction(instance);
}
public static bool Unregister() {
return CriteriaOperator.UnregisterCustomFunction(instance);
}

public string Name => FunctionName;
public string DisplayName => "Does not begin with";
public object Image => "FontSizeDecrease;Office2013";
public string Description =>
"Hides records when the field begins with the given value";
public FunctionCategory Category => FunctionCategory.Text;

public int MinOperandCount => 2;
public int MaxOperandCount => 2;
public bool IsValidOperandCount(int count) => count == 2;
public bool IsValidOperandType(int operandIndex, int operandCount,
Type type) => type == typeof(string);
public Type ResultType(params Type[] operands) => typeof(bool);

public object Evaluate(params object[] operands) {
if(operands[0] != null && operands[1] != null) {
string str1 = operands[0].ToString();
string str2 = operands[1].ToString();
return !str1.StartsWith(str2, StringComparison.InvariantCultureIgnoreCase);
}
return false;
}
}

这是第二个自定义函数InternalDaysOfToday,用于检查DateTime值是否在今天-N天和今天+ N天的时间范围内。

public class WithinDaysOfTodayFunction : ICustomFunctionDisplayAttributes {
public const string FunctionName = "WithinDaysOfToday";
static readonly WithinDaysOfTodayFunction instance =
new WithinDaysOfTodayFunction();
public static void Register() {
CriteriaOperator.RegisterCustomFunction(instance);
}
public static bool Unregister() {
return CriteriaOperator.UnregisterCustomFunction(instance);
}

public string Name => FunctionName;
public string DisplayName => "Within days of today";
public object Image => "SwitchTimeScalesTo;Size16x16;Colored";
public string Description =>
"Shows records when the field value within X days of today";
public FunctionCategory Category => FunctionCategory.DateTime;

public int MinOperandCount => 2;
public int MaxOperandCount => 2;
public bool IsValidOperandCount(int count) => count == 2;
public bool IsValidOperandType(int operandIndex, int operandCount,
Type type) => operandIndex == 0 && type == typeof(DateTime) ||
operandIndex == 1 && type == typeof(int);
public Type ResultType(params Type[] operands) => return typeof(bool);

public object Evaluate(params object[] operands) {
DateTime dt = Convert.ToDateTime(operands[0]);
int days = Convert.ToInt32(operands[1]);
DateTime start = DateTime.Today.AddDays(-days);
DateTime end = DateTime.Today.AddDays(days);
return dt >= start && dt <= end;
}
}

最后,IsWeekend测试DateTime值是星期六还是星期天。

public class IsWeekendFunction : ICustomFunctionDisplayAttributes {
public const string FunctionName = "IsWeekend";
static readonly IsWeekendFunction instance = new IsWeekendFunction();
public static void Register() {
CriteriaOperator.RegisterCustomFunction(instance);
}
public static bool Unregister() {
return CriteriaOperator.UnregisterCustomFunction(instance);
}

public string Name => FunctionName;
public string DisplayName => "Is weekend";
public object Image => "DayView;Office2013";
public string Description =>
"Shows records when the field value is on Saturday or Sunday";
public FunctionCategory Category => FunctionCategory.DateTime;

public int MinOperandCount => 1;
public int MaxOperandCount => 1;
public bool IsValidOperandCount(int count) => count == 1;
public bool IsValidOperandType(int operandIndex, int operandCount,
Type type) => type == typeof(DateTime);
public Type ResultType(params Type[] operands) => typeof(bool);

public object Evaluate(params object[] operands) {
DateTime dt = Convert.ToDateTime(operands[0]);
return dt.DayOfWeek == DayOfWeek.Sunday ||
dt.DayOfWeek == DayOfWeek.Saturday;
}
}


DevExpress v19.2线上公开课即将开课,前10名免费参与哦~

DevExpress技术交流群:540330292      欢迎一起进群讨论

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!