This question continues of this question here, that the answer has gotten a little dense even. The idea is now to better sift through the filtering technique I explained earlier.
In the previous answer, I set up an example in Windows Forms with a screen containing three fields: ownership of the entity to be filtered, operator and condition.
At the click of checkbox Filter, would activate a function also called Filtrar
:
private void checkBoxFiltrar_CheckedChanged(object sender, EventArgs e)
{
Filtrar(checkBoxFiltrar.Checked);
}
The function is below:
protected void Filtrar(bool checkFiltrar)
{
if (checkFiltrar)
clienteBindingSource.DataSource = context.Clientes
.Where(comboBoxCampoPesquisa.SelectedValue.ToString() + ".Contains(@0)", textBoxValor.Text)
.ToList();
else
clienteBindingSource.DataSource = context.Clientes.Local.ToBindingList();
dataGridView.Refresh();
}
Now we must include the logic to insert the correct operator in our code with dynamic LINQ. Before, as we only have columns string
, put an extra operator, called "Contains":
namespace TesteWindowsForms.Models.Enums
{
public enum Condicao
{
[Display(Name = "Contém")]
Contem,
[Display(Name = "Igual")]
Igual,
[Display(Name = "Diferente")]
Diferente,
[Display(Name = "Maior")]
Maior,
[Display(Name = "Menor")]
Menor,
[Display(Name = "Maior ou Igual")]
MaiorOuIgual,
[Display(Name = "Menor ou Igual")]
MenorOuIgual
}
}
The most interesting way I found to implement an operator resolution by Enum
is using Extensions, as the below:
public static class EnumExtensions
{
public static TAttribute GetAttribute<TAttribute>(this Enum enumValue)
where TAttribute : Attribute
{
return enumValue.GetType()
.GetMember(enumValue.ToString())
.First()
.GetCustomAttribute<TAttribute>();
}
public static String CondicaoParaLinq(this Condicao condicao)
{
switch (condicao)
{
case Condicao.Contem:
return ".Contains(@0)";
case Condicao.Diferente:
return " != @0";
case Condicao.Maior:
return " > @0";
case Condicao.MaiorOuIgual:
return " >= @0";
case Condicao.Menor:
return " < @0";
case Condicao.MenorOuIgual:
return " <= @0";
case Condicao.Igual:
default:
return " == @0";
}
}
}
Use:
protected void Filtrar(bool checkFiltrar)
{
if (checkFiltrar)
clienteBindingSource.DataSource = context.Clientes
.Where(comboBoxCampoPesquisa.SelectedValue.ToString() +
((Condicao)Enum.Parse(typeof(Condicao), comboBoxCondicao.SelectedValue.ToString())).CondicaoParaLinq(),
textBoxValor.Text)
.ToList();
else
clienteBindingSource.DataSource = context.Clientes.Local.ToBindingList();
dataGridView1.Refresh();
}
That is, I can filter now by "contains" or "equal" from the screen:
But it doesn’t make much sense to use larger, smaller or smaller or equal, for example, in fields string
, right? It means that every time your search field changes, you will need to restrict operators.
For that, I created this Helper:
public static class CondicoesHelper
{
private static Dictionary<Type, IEnumerable<Condicao>> condicoesPorTipo = new Dictionary<Type, IEnumerable<Condicao>> {
{ typeof(String), new List<Condicao> { Condicao.Igual, Condicao.Diferente, Condicao.Contem } },
{ typeof(int), new List<Condicao> { Condicao.Igual, Condicao.Diferente, Condicao.Maior, Condicao.MaiorOuIgual, Condicao.Menor, Condicao.MenorOuIgual } },
{ typeof(long), new List<Condicao> { Condicao.Igual, Condicao.Diferente, Condicao.Maior, Condicao.MaiorOuIgual, Condicao.Menor, Condicao.MenorOuIgual } },
{ typeof(Guid), new List<Condicao> { Condicao.Igual, Condicao.Diferente } }
};
public static IEnumerable<dynamic> FiltrarCondicoesPorTipoDeCampo(Type tipoDoCampo)
{
return condicoesPorTipo[tipoDoCampo]
.Select(c => new
{
Valor = c.ToString(),
Texto = c.GetAttribute<DisplayAttribute>().Name
})
.AsEnumerable();
}
public static IEnumerable<dynamic> TodasAsCondicoes()
{
return Enum.GetValues(typeof(Condicao))
.Cast<Condicao>()
.Select(c => new
{
Valor = c.ToString(),
Texto = c.GetAttribute<DisplayAttribute>().Name
})
.AsEnumerable();
}
}
Now I will need to tie an event to the search field. When it changes, the conditions list should be updated. That is:
private void comboBoxCampoPesquisa_SelectedValueChanged(object sender, EventArgs e)
{
IEnumerable<dynamic> condicoes;
if (comboBoxCampoPesquisa.SelectedValue != null)
{
condicoes = CondicoesHelper.FiltrarCondicoesPorTipoDeCampo(typeof(Cliente).GetProperty(comboBoxCampoPesquisa.SelectedValue.ToString()).PropertyType);
} else
{
condicoes = CondicoesHelper.TodasAsCondicoes();
}
comboBoxCondicao.ValueMember = "Valor";
comboBoxCondicao.DisplayMember = "Texto";
comboBoxCondicao.DataSource = condicoes.ToList();
}
Once this has been done, I can comment on the fulfilment of the OnLoad
:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
context.Clientes.Load();
clienteBindingSource.DataSource =
context.Clientes.Local.ToBindingList();
var camposPesquisa =
typeof(Cliente).GetProperties(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public |
BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)
.Select(p => new
{
Valor = p.Name,
Texto = p.GetCustomAttribute<DisplayNameAttribute>().DisplayName
}).ToList();
comboBoxCampoPesquisa.ValueMember = "Valor";
comboBoxCampoPesquisa.DisplayMember = "Texto";
comboBoxCampoPesquisa.DataSource = camposPesquisa;
//var condicoes = Enum.GetValues(typeof(Condicao))
// .Cast<Condicao>()
// .Select(c => new
// {
// Valor = c.ToString(),
// Texto = c.GetAttribute<DisplayAttribute>().Name
// })
// .ToList();
//comboBoxCondicao.ValueMember = "Valor";
//comboBoxCondicao.DisplayMember = "Texto";
//comboBoxCondicao.DataSource = condicoes;
viewModel = new FiltrosPesquisaViewModel
{
};
}
And the method Filtrar
? Stay like this:
protected void Filtrar(bool checkFiltrar)
{
if (checkFiltrar)
clienteBindingSource.DataSource = context.Clientes
.Where(comboBoxCampoPesquisa.SelectedValue.ToString() +
((Condicao)Enum.Parse(typeof(Condicao), comboBoxCondicao.SelectedValue.ToString())).CondicaoParaLinq(),
Convert.ChangeType(textBoxValor.Text, typeof(Cliente).GetProperty(comboBoxCampoPesquisa.SelectedValue.ToString()).PropertyType))
.ToList();
else
clienteBindingSource.DataSource = context.Clientes.Local.ToBindingList();
dataGridView1.Refresh();
}
To test, I put an extra column on the screen, "Number of Users", which is integer:
Finally, the operators are filtered according to the field type:
Let’s get back to what we talked about here, right?
– Leonel Sanches da Silva
@Gypsy omorrisonmendez excuse guy was my mistake, I thought I could not reference the question another link . I edited and put the question referenced
– Aprendiz