none
Filtrar lista genérica de clases usando todas sus propiedades con campos específicos RRS feed

  • Pregunta

  • Hola:

     Tengo una lista generica de clases con la cual cargo un control DataGridView, posterior a la carga inicial tengo la necesidad de aplicar un filtro usando varios combobox, Servicio, Etapa, Persona, el usuario puede seleccionar uno o todos los controles para aplicar el filtro y el control DataGridView tiene que mostrar estos valores, no tengo problemas en filtrar la lista usando un solo campo pero se me esta complicando cuando quiero usar mas de un control para aplicar el filtro, este es mi codigo de ejemplo:

            private void Filtrar()
            {
    
                var entidadServicio = cmboxServicio.SelectedItem as Entidad;
                var entidadEtapa = cmboxEtapa.SelectedItem as Entidad;
                var entidadTipoPersona = cmboxTipoPersona.SelectedItem as Entidad;
    
                var query = (from x in _lista
                            where ((!entidadServicio.Valor.Equal("<<<Seleccione>>>") && x.Servicio.Equal(entidadServicio.Valor))
                            || (!entidadEtapa.Valor.Equal("<<<Seleccione>>>") && x.Etapa.Equal(entidadEtapa.Valor))
                            || (!entidadTipoPersona.Valor.Equal("<<<Seleccione>>>") && x.TipoPersona.Equal(entidadTipoPersona.Valor)))
                            select x).ToList();
    
                dgvChecklist.DataSource = null;
                dgvChecklist.Rows.Clear();
                dgvChecklist.DataSource = query;
            }

     Quiero que la lista se filtre usando uno, dos, tres o todos los controles, algo similar a un AND en sql.

    ¿Alguna idea de como realizar esto?


    Saludos desde Monterrey, Nuevo León, México!!!



    sábado, 6 de octubre de 2018 20:50

Respuestas

  • Deleted
    sábado, 6 de octubre de 2018 23:01
  • Hola nuevamente:

     Replanteo mi pregunta para darles un mejor contexto.

    Tengo la siguiente clase:

        public class MyClass
        {
            public int Numero { get; set; }
            public string Nombre { get; set; }
            public string Apellido { get; set; }
        }

     Lleno una lista generica con informacion que obtengo de una tabla:

                var myList = new List<MyClass>();
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 1", Apellido = "Apellido1" });
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 1", Apellido = "Apellido1" });
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 31", Apellido = "Apellido1" });
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 31", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 3, Nombre = "Nombre 3", Apellido = "Apellido3" });
                myList.Add(new MyClass() { Numero = 3, Nombre = "Nombre 3", Apellido = "Apellido3" });
                myList.Add(new MyClass() { Numero = 3, Nombre = "Nombre 3", Apellido = "Apellido3" });

     Ahora imageneN que tengo 3 combobox cargados con un SELECT DISTINCT [RespectivoCampo] FROM Tabla desde donde quiero aplicar filtros a esta lista, los bindings de los ComboBox son diferentes a la lista que quiero filtrar y el resultado mostrarlo en un control DataGridView.

     Bien, el problema esta en que no encuentro la manera mas idonea de filtrar por una o todas las propiedades de la clase contenida en mi lista.

     Un ejemplo de lo que quiero es: En el combobox Numero seleccionar "1", en el combobox Nombre seleccionar "Nombre 31" y en el combox Apellido seleccionar "Apellido2", esta accion me debe de traer este elemento.

    myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 31", Apellido = "Apellido2" });

    Pero si seleccionara: En el combobox Numero seleccionar "1" y en el combox Apellido seleccionar "Apellido2"

    myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 31", Apellido = "Apellido2" });
    myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 2", Apellido = "Apellido2" });

    Bien ese es el resultado al que  quiero llegar, cabe mencionar que myList es una variable a nivel de clase, mis combobox tienen bindings separados y usan una clase llamada Entidad (con dos propiedades Id y Valor), tienen un primer elemento "<<<Seleccione>>>".

    Este es mi codigo de avance:

            private void Filtrar()
            {
    
                var entidadNombre = cmboxNombre.SelectedItem as Entidad;
                var entidadNumero = cmboxNumero.SelectedItem as Entidad;
                var entidadApellido = cmboxApellido.SelectedItem as Entidad;
    
                var query = (from x in _lista
                            where ((!entidadNombre.Valor.Equal("<<<Seleccione>>>") && x.Servicio.Equal(entidadNombre.Valor))
                            || (!entidadNumero.Valor.Equal("<<<Seleccione>>>") && x.Etapa.Equal(entidadNumero.Valor))
                            || (!entidadApellido.Valor.Equal("<<<Seleccione>>>") && x.TipoPersona.Equal(entidadApellido.Valor)))
                            select x).ToList();
    
                dgvChecklist.DataSource = null;
                dgvChecklist.Rows.Clear();
                dgvChecklist.DataSource = query;
            }
     Con el cual no obtengo el resultado deseado.


    Saludos desde Monterrey, Nuevo León, México!!!

    domingo, 7 de octubre de 2018 18:12
  • No estoy seguro porque siempre lo hago sobre listas tipadas. Para hacerlo a mi modo debería conocer el tipo de objetos con que se cargó "_lista". Aún así arriesgo una propuesta, algo así:

    var query = (from x in _lista where 
    x.Servicio.Valor == entidadServicio.Valor || 
    x.Etapa.Valor == entidadEtapa.Valor || 
    x.TipoPersona.Valor == entidadTipoPersona.Valor 
    select x).ToList();

    domingo, 7 de octubre de 2018 0:13
  • Probablemente te sea mas sencillo separar las condiciones, prueba con algo así:

    IEnumerable<MyClass> query = myList.AsEnumerable();
    if (entidadNombre.Valor != "<<<Seleccione>>>") query= query.Where(m => m.Servicio == entidadNombre.Valor);
    if (entidadNumero.Valor != "<<<Seleccionar>>>") query = query.Where(m => m.Etapa == entidadNumero.Valor);
    if (entidadApellido.Valor != "<<<Seleccionar>>>") query = query.Where(m => m.TipoPersona == entidadApellido.Valor);

    dgvChecklist.DataSoource = query.ToList();

    Saludos,

    Anibal Marcano

    lunes, 8 de octubre de 2018 7:46

Todas las respuestas

  • Deleted
    sábado, 6 de octubre de 2018 23:01
  • No estoy seguro porque siempre lo hago sobre listas tipadas. Para hacerlo a mi modo debería conocer el tipo de objetos con que se cargó "_lista". Aún así arriesgo una propuesta, algo así:

    var query = (from x in _lista where 
    x.Servicio.Valor == entidadServicio.Valor || 
    x.Etapa.Valor == entidadEtapa.Valor || 
    x.TipoPersona.Valor == entidadTipoPersona.Valor 
    select x).ToList();

    domingo, 7 de octubre de 2018 0:13
  • Hola nuevamente:

     Replanteo mi pregunta para darles un mejor contexto.

    Tengo la siguiente clase:

        public class MyClass
        {
            public int Numero { get; set; }
            public string Nombre { get; set; }
            public string Apellido { get; set; }
        }

     Lleno una lista generica con informacion que obtengo de una tabla:

                var myList = new List<MyClass>();
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 1", Apellido = "Apellido1" });
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 1", Apellido = "Apellido1" });
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 31", Apellido = "Apellido1" });
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 31", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 2, Nombre = "Nombre 2", Apellido = "Apellido2" });
                myList.Add(new MyClass() { Numero = 3, Nombre = "Nombre 3", Apellido = "Apellido3" });
                myList.Add(new MyClass() { Numero = 3, Nombre = "Nombre 3", Apellido = "Apellido3" });
                myList.Add(new MyClass() { Numero = 3, Nombre = "Nombre 3", Apellido = "Apellido3" });

     Ahora imageneN que tengo 3 combobox cargados con un SELECT DISTINCT [RespectivoCampo] FROM Tabla desde donde quiero aplicar filtros a esta lista, los bindings de los ComboBox son diferentes a la lista que quiero filtrar y el resultado mostrarlo en un control DataGridView.

     Bien, el problema esta en que no encuentro la manera mas idonea de filtrar por una o todas las propiedades de la clase contenida en mi lista.

     Un ejemplo de lo que quiero es: En el combobox Numero seleccionar "1", en el combobox Nombre seleccionar "Nombre 31" y en el combox Apellido seleccionar "Apellido2", esta accion me debe de traer este elemento.

    myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 31", Apellido = "Apellido2" });

    Pero si seleccionara: En el combobox Numero seleccionar "1" y en el combox Apellido seleccionar "Apellido2"

    myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 31", Apellido = "Apellido2" });
    myList.Add(new MyClass() { Numero = 1, Nombre = "Nombre 2", Apellido = "Apellido2" });

    Bien ese es el resultado al que  quiero llegar, cabe mencionar que myList es una variable a nivel de clase, mis combobox tienen bindings separados y usan una clase llamada Entidad (con dos propiedades Id y Valor), tienen un primer elemento "<<<Seleccione>>>".

    Este es mi codigo de avance:

            private void Filtrar()
            {
    
                var entidadNombre = cmboxNombre.SelectedItem as Entidad;
                var entidadNumero = cmboxNumero.SelectedItem as Entidad;
                var entidadApellido = cmboxApellido.SelectedItem as Entidad;
    
                var query = (from x in _lista
                            where ((!entidadNombre.Valor.Equal("<<<Seleccione>>>") && x.Servicio.Equal(entidadNombre.Valor))
                            || (!entidadNumero.Valor.Equal("<<<Seleccione>>>") && x.Etapa.Equal(entidadNumero.Valor))
                            || (!entidadApellido.Valor.Equal("<<<Seleccione>>>") && x.TipoPersona.Equal(entidadApellido.Valor)))
                            select x).ToList();
    
                dgvChecklist.DataSource = null;
                dgvChecklist.Rows.Clear();
                dgvChecklist.DataSource = query;
            }
     Con el cual no obtengo el resultado deseado.


    Saludos desde Monterrey, Nuevo León, México!!!

    domingo, 7 de octubre de 2018 18:12
  • Cambié un poco la clase y la notación para hacer una prueba. Creo que te puede sevir.

    namespace FiltrarLista
    {
      public partial class Form1 : Form
      {
          
        public Form1()
        {
          InitializeComponent(); 
        }
    
        List<MyClass> myList;
        
        private void Form1_Load(object sender, EventArgs e)
        {
          myList = new List<MyClass>();
          myList.Add(new MyClass() { Servicio = "1", Etapa = "Nombre 1", TipoPersona = "Apellido1" });
          myList.Add(new MyClass() { Servicio = "1", Etapa = "Nombre 1", TipoPersona = "Apellido1" });
          myList.Add(new MyClass() { Servicio = "1", Etapa = "Nombre 31", TipoPersona = "Apellido1" });
          myList.Add(new MyClass() { Servicio = "1", Etapa = "Nombre 31", TipoPersona = "Apellido2" });
          myList.Add(new MyClass() { Servicio = "1", Etapa = "Nombre 2", TipoPersona = "Apellido2" });
          myList.Add(new MyClass() { Servicio = "2", Etapa = "Nombre 2", TipoPersona = "Apellido2" });
          myList.Add(new MyClass() { Servicio = "2", Etapa = "Nombre 2", TipoPersona = "Apellido2" });
          myList.Add(new MyClass() { Servicio = "2", Etapa = "Nombre 2", TipoPersona = "Apellido2" });
          myList.Add(new MyClass() { Servicio = "2", Etapa = "Nombre 2", TipoPersona = "Apellido2" });
          myList.Add(new MyClass() { Servicio = "2", Etapa = "Nombre 2", TipoPersona = "Apellido2" });
          myList.Add(new MyClass() { Servicio = "3", Etapa = "Nombre 3", TipoPersona = "Apellido3" });
          myList.Add(new MyClass() { Servicio = "3", Etapa = "Nombre 3", TipoPersona = "Apellido3" });
          myList.Add(new MyClass() { Servicio = "3", Etapa = "Nombre 3", TipoPersona = "Apellido3" });
    
                  
          dgv.DataSource = myList;
            
          var lstServ = myList.Select(x => x.Servicio).Distinct().ToList();
          lstServ.Insert(0, "<<<Seleccionar>>>");
          cbServicio.DataSource = lstServ;
    
          var lstEtapa = myList.Select(x => x.Etapa).Distinct().ToList();
          lstEtapa.Insert(0, "<<<Seleccionar>>>");
          cbEtapa.DataSource = lstEtapa;
    
          var lstTipPers= myList.Select(x => x.TipoPersona).Distinct().ToList();
          lstTipPers.Insert(0, "<<<Seleccionar>>>");
          cbTipoPersona.DataSource = lstTipPers;
        }
    
        private void txtFiltrar_Click(object sender, EventArgs e)
        {
          Filtrar();
        }
    
        private void Filtrar()
        {
          String Serv = cbServicio.SelectedItem.ToString();
          String Etpa = cbEtapa.SelectedItem.ToString();
          String TPers = cbTipoPersona.SelectedItem.ToString();
    
          var query = (from x in myList
                       where (Serv != "<<<Seleccionar>>>" && Etpa != "<<<Seleccionar>>>" && TPers != "<<<Seleccionar>>>" && x.Servicio == Serv && x.Etapa == Etpa && x.TipoPersona == TPers)
                          || (Serv != "<<<Seleccionar>>>" && Etpa != "<<<Seleccionar>>>" && TPers == "<<<Seleccionar>>>" && x.Servicio == Serv && x.Etapa == Etpa)
                          || (Serv != "<<<Seleccionar>>>" && Etpa == "<<<Seleccionar>>>" && TPers != "<<<Seleccionar>>>" && x.Servicio == Serv && x.TipoPersona == TPers)
                          || (Serv == "<<<Seleccionar>>>" && Etpa != "<<<Seleccionar>>>" && TPers != "<<<Seleccionar>>>" && x.Etapa == Etpa && x.TipoPersona == TPers)
                          || (Serv != "<<<Seleccionar>>>" && Etpa == "<<<Seleccionar>>>" && TPers == "<<<Seleccionar>>>" && x.Servicio == Serv)
                          || (Serv == "<<<Seleccionar>>>" && Etpa != "<<<Seleccionar>>>" && TPers == "<<<Seleccionar>>>" && x.Etapa == Etpa)
                          || (Serv == "<<<Seleccionar>>>" && Etpa == "<<<Seleccionar>>>" && TPers != "<<<Seleccionar>>>" && x.TipoPersona == TPers)
                          || (Serv == "<<<Seleccionar>>>" && Etpa == "<<<Seleccionar>>>" && TPers == "<<<Seleccionar>>>")
                       select x).ToList();
    
          dgv.DataSource = null;
          dgv.Rows.Clear();
          dgv.DataSource = query;
        }
      }
    
    
      public class MyClass
      {
        public String Servicio { get; set; }
        public string Etapa { get; set; }
        public string TipoPersona { get; set; }
      }
    }



    lunes, 8 de octubre de 2018 1:29
  • Probablemente te sea mas sencillo separar las condiciones, prueba con algo así:

    IEnumerable<MyClass> query = myList.AsEnumerable();
    if (entidadNombre.Valor != "<<<Seleccione>>>") query= query.Where(m => m.Servicio == entidadNombre.Valor);
    if (entidadNumero.Valor != "<<<Seleccionar>>>") query = query.Where(m => m.Etapa == entidadNumero.Valor);
    if (entidadApellido.Valor != "<<<Seleccionar>>>") query = query.Where(m => m.TipoPersona == entidadApellido.Valor);

    dgvChecklist.DataSoource = query.ToList();

    Saludos,

    Anibal Marcano

    lunes, 8 de octubre de 2018 7:46