static public BaseNode BuildFromExpression(Expression expr, BaseNode parent = null, bool negate = false) { CriteriaNode result; switch (GetConditionType(expr)) { // Structural nodes: case NodeType.Multi: return(BuildMulti(expr as BinaryExpression, parent, negate)); case NodeType.Negatable: return(BuildNegatable(expr as UnaryExpression)); default: if (parent != null) { parent.HasUnparsedChilds = true; } return(new UnparsedNode { Expression = expr, Negate = negate }); // Criteria Nodes (leafs): case NodeType.TrueCriteria: result = new CriteriaNode(expr as MemberExpression); break; case NodeType.LeftCriteria: var be = expr as BinaryExpression; result = new CriteriaNode(be.Left as MemberExpression, be.Right as ConstantExpression, expr.NodeType); break; case NodeType.RightCriteria: var be2 = expr as BinaryExpression; var nt = expr.NodeType; if (nt == ExpressionType.LessThan) { nt = ExpressionType.GreaterThan; } else if (nt == ExpressionType.LessThanOrEqual) { nt = ExpressionType.GreaterThanOrEqual; } else if (nt == ExpressionType.GreaterThan) { nt = ExpressionType.LessThan; } else if (nt == ExpressionType.GreaterThanOrEqual) { nt = ExpressionType.LessThanOrEqual; } result = new CriteriaNode(be2.Right as MemberExpression, be2.Left as ConstantExpression, nt); break; case NodeType.MethodCriteria: result = BuildMethodCriteria(expr as MethodCallExpression); break; case NodeType.StringCompareCriteria: var be3 = expr as BinaryExpression; result = BuildMethodCriteria(be3.Left as MethodCallExpression); switch (be3.NodeType) { case ExpressionType.Equal: result.Op = Operator.E; break; case ExpressionType.LessThan: result.Op = Operator.LT; break; case ExpressionType.LessThanOrEqual: result.Op = Operator.LToE; break; case ExpressionType.GreaterThan: result.Op = Operator.GT; break; case ExpressionType.GreaterThanOrEqual: result.Op = Operator.GToE; break; case ExpressionType.NotEqual: result.Op = Operator.NE; break; default: throw new NotSupportedException(); } break; } if (negate) { result.Op = result.Op.Negate(); } return(result); }
public CriteriaNodePanel(Type baseType, Panel parent, CriteriaNode node) : base(parent, node) { Node = node; flow = new FlowLayoutPanel { FlowDirection = FlowDirection.LeftToRight, Dock = DockStyle.Fill, ContextMenuStrip = this.ContextMenuStrip }; // Operator: operatorCombo = new ComboBox() { DropDownStyle = ComboBoxStyle.DropDownList, Margin = new Padding(2, MarginTop, 2, 0), Width = CalcWidth(node.Op.GetName()), DropDownWidth = SuggestedOperatorComboBoxWidth() }; operatorCombo.SelectionChangeCommitted += OperatorChanged; // Value (combobox for enum object types): valueComboBox = new ComboBox() { DropDownStyle = ComboBoxStyle.DropDownList, Margin = new Padding(2, MarginTop, 2, 0), DropDownWidth = 120 }; valueComboBox.SelectionChangeCommitted += (s, e) => node.Value = valueComboBox.SelectedItem; // Value (textbox for non-enum object types): valueTextBox = new TextBox() { Margin = new Padding(2, MarginTop + 1, 2, 0), Width = 100 }; valueTextBox.LostFocus += (s, e) => { node.Value = valueTextBox.Text; }; if (node.Value != null) { valueTextBox.Text = node.Value.ToString(); } // Checkbox for case sensitivity for string criteria: valueCaseSensitivity = new CheckBox() { Text = "Case sensitive", Margin = new Padding(2, MarginTop + 3, 2, 0), AutoSize = true, Checked = node.CaseSensitive }; valueCaseSensitivity.CheckedChanged += (s, e) => { node.CaseSensitive = valueCaseSensitivity.Checked; }; // First property combobox which always appears, based on baseType (last item in stack): var firstPropValue = node.IsBlank ? null : node.PropertyPath.Last().Member.Name; AddPropCombo(flow, firstPropValue, baseType); if (firstPropValue != null) { // Sequence of sub-properties (may appear 0..x times based on how deep we go): if (node.PropertyPath.Count > 1) { var i = 1; foreach (var p in node.PropertyPath.Reverse().Skip(1)) { AddPropCombo(flow, p.Member.Name, p.Member.ReflectedType); i++; } } } flow.Controls.Add(operatorCombo); flow.Controls.Add(valueComboBox); flow.Controls.Add(valueTextBox); flow.Controls.Add(valueCaseSensitivity); Controls.Add(flow); if (Node.PropertyPath.Count == 0) { Node.PropertyPath.Push(new CriteriaNode.PropertyPathItem()); } UpdateOperatorAndValue(); flow.Paint += Flow_Paint; }
static private CriteriaNode BuildMethodCriteria(MethodCallExpression mce) { CriteriaNode result; // Support for standard string methods (contains, ends with, starts with, etc.): if (mce.Method.DeclaringType == typeof(string)) { var res = new CriteriaNode(); switch (mce.Method.Name) { case "StartsWith": case "EndsWith": res.CaseSensitive = !(mce.Arguments.Count == 3 && mce.Arguments[1] is ConstantExpression && (bool)(mce.Arguments[1] as ConstantExpression).Value); res.Value = (mce.Arguments[0] as ConstantExpression).Value.ToString(); res.Op = mce.Method.Name == "StartsWith" ? Operator.StartsWith : Operator.EndsWith; CriteriaNode.GetPropertyPath(mce.Object as MemberExpression).ForEach(ppi => res.PropertyPath.Push(ppi)); break; case "IsNullOrEmpty": res.CaseSensitive = false; res.Op = Operator.IsBlank; CriteriaNode.GetPropertyPath(mce.Arguments[0] as MemberExpression).ForEach(ppi => res.PropertyPath.Push(ppi)); break; case "Contains": // The string Contains() method is always case sensitive: res.CaseSensitive = true; res.Value = (mce.Arguments[0] as ConstantExpression).Value.ToString(); res.Op = Operator.Contains; CriteriaNode.GetPropertyPath(mce.Object as MemberExpression).ForEach(ppi => res.PropertyPath.Push(ppi)); break; case "Compare": res.CaseSensitive = false; if (mce.Arguments.Count == 3) { res.CaseSensitive = !(bool)(mce.Arguments[2] as ConstantExpression).Value; } res.Value = (mce.Arguments[1] as ConstantExpression).Value.ToString(); CriteriaNode.GetPropertyPath(mce.Arguments[0] as MemberExpression).ForEach(ppi => res.PropertyPath.Push(ppi)); break; case "IndexOf": // For case insensitive comparisons, the IndexOf method can be used: res.CaseSensitive = true; if ( mce.Arguments.Count == 2 && mce.Arguments[1] is ConstantExpression && (mce.Arguments[1] as ConstantExpression).Type == typeof(StringComparison)) { var ct = (StringComparison)(mce.Arguments[1] as ConstantExpression).Value; switch (ct) { case StringComparison.CurrentCultureIgnoreCase: case StringComparison.InvariantCultureIgnoreCase: case StringComparison.OrdinalIgnoreCase: res.CaseSensitive = false; break; } } res.Value = (mce.Arguments[0] as ConstantExpression).Value.ToString(); res.Op = Operator.Contains; CriteriaNode.GetPropertyPath(mce.Object as MemberExpression).ForEach(ppi => res.PropertyPath.Push(ppi)); break; } result = res; } else if (mce.Method.DeclaringType == typeof(System.Text.RegularExpressions.Regex)) { var res = new CriteriaNode(); if (mce.Method.Name == "IsMatch" && mce.Arguments.Count == 2 && mce.Arguments[1].Type == typeof(string)) { res.CaseSensitive = true; res.Op = Operator.RegExMatch; res.Value = (mce.Arguments[1] as ConstantExpression).Value.ToString(); CriteriaNode.GetPropertyPath(mce.Arguments[0] as MemberExpression).ForEach(ppi => res.PropertyPath.Push(ppi)); } else { return(null); } result = res; } else { // Other methods not supported: return(null); } return(result); }