Пользовательские фильтры / запросы?

Я пытаюсь найти способ разрешить пользователям моего приложения определять свои собственные запросы или фильтры, которые можно применять к коллекции. Я хочу в конечном итоге предоставить интуитивно понятный пользовательский интерфейс для создания этих фильтров (см. Изображение ниже), но сначала было бы нормально, если бы пользователю нужно было ввести строку текстового запроса. Мне также нужно иметь возможность сериализовать эти определенные пользователем запросы в строку, чтобы я мог сохранить их вместе с остальной информацией о проекте.

Пример пользовательского интерфейса http://dl.dropbox.com/u/113068/filterUI.jpg

Я ищу тип функциональности, которую вы бы получили от чего-то вроде SQL-запроса, например числовых условий (меньше, больше), строкового условия (содержит, начинается с, заканчивается) или логического условия (истина или ложь ). Я также хотел бы иметь возможность группировать условия, используя логическую логику, такую ​​как OR, AND и NOT.

Я начал рисовать, как бы сделать это с нуля, используя такие классы, как NodeFilter, AbsNodeCondition, NodeStringCondition, NodeConditionOrJoin и т.д. У меня не было возможности провести с ним много времени.

Могу ли я каким-то образом разрешить пользователю вводить запрос Linq к объектам в текстовом поле, а затем программно превращать строку в реальный запрос Linq, который можно применить к моей коллекции? Или есть другой способ разрешить пользователю создавать и сохранять запросы? Мне также понадобится способ сериализации фильтра / запроса в строку, чтобы я мог сохранить его вместе с остальной информацией о программе.


person Eric Anastas    schedule 18.12.2009    source источник
comment
Ссылка на пример пользовательского интерфейса не работает. Можно ли будет загрузить новую картинку?   -  person David    schedule 17.03.2017


Ответы (2)


Это не обязательно идеальное решение, но проект MetaLinq предоставляет сериализуемые оболочки для классов выражений LINQ.

Вот пример того, как вы можете воссоздать и выполнить выражение после его сериализации в оба конца.

Сначала мы сериализуем существующее выражение lamba в XML-документ.

var originalExpr = EditableExpression.CreateEditableExpression<string, bool>(
    str => str.Length > 3);
var serializer = new XmlSerializer(originalExpr.GetType());
string xml;

using (var writer = new StringWriter())
{
    serializer.Serialize(writer, originalExpr);
    xml = writer.ToString();
}

Затем мы десериализуем, разворачиваем и компилируем его обратно в делегат, готовый к выполнению.

EditableExpression newExpr;

using (var reader = new StringReader(xml))
{
    newExpr = (EditableExpression) serializer.Deserialize(reader);
}

var expr = (Expression<Func<string, bool>>) newExpr.ToExpression();
var items = new[] {"one", "two", "three"};
var result = items.Count(expr.Compile());
Debug.Assert(result == 1);

Так выглядит сериализованное выражение.

<EditableLambdaExpression xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <NodeType>Lambda</NodeType>
  <TypeName>System.Func`2[[System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089],[System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]], System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</TypeName>
  <Body xsi:type="EditableBinaryExpression">
    <NodeType>GreaterThan</NodeType>
    <TypeName>System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</TypeName>
    <Left xsi:type="EditableMemberExpression">
      <NodeType>MemberAccess</NodeType>
      <Expression xsi:type="EditableParameterExpression">
        <NodeType>Parameter</NodeType>
        <TypeName>System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</TypeName>
        <Name>str</Name>
      </Expression>
      <MemberName>System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Int32 Length</MemberName>
    </Left>
    <Right xsi:type="EditableConstantExpression">
      <NodeType>Constant</NodeType>
      <Value xsi:type="xsd:int">3</Value>
    </Right>
  </Body>
  <Parameters>
    <EditableExpression xsi:type="EditableParameterExpression">
      <NodeType>Parameter</NodeType>
      <TypeName>System.String, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</TypeName>
      <Name>str</Name>
    </EditableExpression>
  </Parameters>
</EditableLambdaExpression>
person Nathan Baulch    schedule 18.12.2009

System.Linq.Expressions, к сожалению, не сериализуем, даже в 4.0. Вам придется прибегнуть к написанию собственных деревьев выражений и посетителей для генерации запросов из них, если вам нужно пересечь границы домена приложения. В противном случае деревья выражения в блоке будут в порядке.

Кроме того, вы можете найти динамический linq, который несколько подходит для ваших нужд.

person Tanveer Badar    schedule 30.12.2009