seleccion - no permitir ordenar columnas datagridview c#
¿Cómo habilitar la ordenación de DataGridView cuando el usuario hace clic en el encabezado de la columna? (14)
Crea una clase que contenga todas las propiedades que necesites y cuélalas en el constructor
class Student { int _StudentId; public int StudentId {get;} string _Name; public string Name {get;} ... public Student(int studentId, string name ...) { _StudentId = studentId; _Name = name; ... } }
Cree una clase IComparer <Estudiante> para poder ordenar
class StudentSorter : IComparer<Student> { public enum SField {StudentId, Name ... } SField _sField; SortOrder _sortOrder; public StudentSorder(SField field, SortOrder order) { _sField = field; _sortOrder = order;} public int Compare(Student x, Student y) { if (_SortOrder == SortOrder.Descending) { Student tmp = x; x = y; y = tmp; } if (x == null || y == null) return 0; int result = 0; switch (_sField) { case SField.StudentId: result = x.StudentId.CompareTo(y.StudentId); break; case SField.Name: result = x.Name.CompareTo(y.Name); break; ... } return result; } }
Dentro del formulario que contiene la cuadrícula de datos agregar
ListDictionary sortOrderLD = new ListDictionary(); //if less than 10 columns private SortOrder SetOrderDirection(string column) { if (sortOrderLD.Contains(column)) { sortOrderLD[column] = (SortOrder)sortOrderLD[column] == SortOrder.Ascending ? SortOrder.Descending : SortOrder.Ascending; } else { sortOrderLD.Add(column, SortOrder.Ascending); } return (SortOrder)sortOrderLD[column]; }
Dentro del controlador de eventos datagridview_ColumnHeaderMouseClick haz algo como esto
private void dgv_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e) { StudentSorter sorter = null; string column = dGV.Columns[e.ColumnIndex].DataPropertyName; //Use column name if you set it if (column == "StudentId") { sorter = new StudentSorter(StudentSorter.SField.StudentId, SetOrderDirection(column)); } else if (column == "Name") { sorter = new StudentSorter(StudentSorter.SField.Name, SetOrderDirection(column)); } ... List<Student> lstFD = datagridview.DataSource as List<Student>; lstFD.Sort(sorter); datagridview.DataSource = lstFD; datagridview.Refresh(); }
Espero que esto ayude
Tengo una vista de cuadrícula de datos en mi formulario y la lleno con esto:
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
.OrderBy(s => s.Apellidos)
.ToList();
Ahora, utilizo el nombre en el orden predeterminado, pero también me gustaría permitir que los usuarios clasifiquen al hacer clic en el encabezado de la columna.
Este tipo no modificará los datos de ninguna manera, es solo una bonificación del lado del cliente para permitir una búsqueda más fácil de información al escanear la pantalla con sus ojos.
Gracias por las sugerencias.
Como sugirió Niraj, use una SortableBindingList . Lo he usado con mucho éxito con DataGridView.
Aquí hay un enlace al código actualizado que utilicé - Presentando SortableBindingList - Take Two
Simplemente agregue los dos archivos fuente a su proyecto y estará en el negocio.
La fuente está en SortableBindingList.zip
Establezca todas las columnas (que pueden ser clasificadas por los usuarios) la propiedad SortMode en Automático
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth })
.OrderBy(s => s.Apellidos)
.ToList();
foreach(DataGridViewColumn column in dataGridView1.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
Editar: como su vista de cuadrícula de datos está vinculada con una consulta de linq, no será ordenada. Por lo tanto, vaya a este link que explica cómo crear una lista de enlace ordenable y luego alimentarlo como fuente de datos a datagridview.
No necesita crear un origen de datos vinculante. Si desea aplicar la clasificación para todas sus columnas, aquí hay una solución mía más genérica;
private int _previousIndex;
private bool _sortDirection;
private void gridView_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex == _previousIndex)
_sortDirection ^= true; // toggle direction
gridView.DataSource = SortData(
(List<MainGridViewModel>)gridReview.DataSource, gridReview.Columns[e.ColumnIndex].Name, _sortDirection);
_previousIndex = e.ColumnIndex;
}
public List<MainGridViewModel> SortData(List<MainGridViewModel> list, string column, bool ascending)
{
return ascending ?
list.OrderBy(_ => _.GetType().GetProperty(column).GetValue(_)).ToList() :
list.OrderByDescending(_ => _.GetType().GetProperty(column).GetValue(_)).ToList();
}
Asegúrese de suscribir su cuadrícula de datos al evento ColumnHeaderMouseClick
. Cuando el usuario hace clic en la columna, ordenará descendiendo. Si se vuelve a hacer clic en el mismo encabezado de columna, la clasificación se aplicará por ascensión.
Por si acaso alguien todavía lo busca, lo hice en VS 2008 C #.
En Event ColumnHeaderMouseClick, agregue un enlace de datos para gridview y envíe el orden por campo como un parámetro. Puede obtener el campo cliqueado de la siguiente manera:
dgView.Columns[e.ColumnIndex].Name
En mi caso, los nombres de los encabezados son similares a los nombres de los campos de vista.
Puede usar el evento DataGridViewColoumnHeaderMouseClick de la siguiente manera:
Private string order = String.Empty;
private void dgvDepartment_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (order == "d")
{
order = "a";
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth }) .OrderBy(s => s.Apellidos).ToList();
}
else
{
order = "d";
dataGridView1.DataSource = students.Select(s => new { ID = s.StudentId, RUDE = s.RUDE, Nombre = s.Name, Apellidos = s.LastNameFather + " " + s.LastNameMother, Nacido = s.DateOfBirth }.OrderByDescending(s => s.Apellidos) .ToList()
}
}
Si aparece un mensaje de error como
Se produjo una excepción no controlada del tipo ''System.NullReferenceException'' en System.Windows.Forms.dll
si trabajas con SortableBindingList, tu código probablemente use algunos bucles sobre las filas de DataGridView y también intente acceder a la última fila vacía. (BindingSource = null)
Si no necesita permitir que el usuario agregue nuevas filas directamente en DataGridView, esta línea de código resuelve fácilmente el problema:
InitializeComponent();
m_dataGridView.AllowUserToAddRows = false; // after components initialized
...
Sugiero usar DataTable.DefaultView como un DataSource. Luego la línea de abajo.
foreach (DataGridViewColumn column in gridview.Columns)
{
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
Después de eso, la vista en cuadrícula administrará la clasificación (se admite Ascendente o Descendente).
Tengo una vinculación de objeto BindingList <> como fuente de datos para dataGridView.
BindingList x1;
x1 = new BindingList<sourceObject>();
BindingSource bsx1 = new BindingSource();
bsx1.DataSource = x1;
dataGridView1.DataSource = bsx1;
Cuando hice clic en el encabezado de la columna, no se realizó ninguna clasificación. Utilicé la respuesta SortableBindingList proporcionada por Tom Bushell. Después de haber incluido dos archivos fuente en mi proyecto
- SortableBindingList.cs
- PropertyComparer.cs
Entonces este cambio se hace a mi código:
Be.Timvw.Framework.ComponentModel.SortableBindingList x1; // 1
x1 = new Be.Timvw.Framework.ComponentModel.SortableBindingList<sourceObject>(); // 2
BindingSource bsx1 = new BindingSource();
bsx1.DataSource = x1;
dataGridView1.DataSource = bsx1;
Después de estos cambios, realicé una compilación en mi programa. Ahora puedo ordenar haciendo clic en los encabezados de las columnas. Solo dos líneas deben cambiar, se destacan en el fragmento de código anterior mediante comentarios finales.
Una forma más de hacerlo es usar la biblioteca "System.Linq.Dynamic". Puedes obtener esta biblioteca de Nuget. No hay necesidad de implementaciones personalizadas :).
using System.Linq.Dynamic;
private bool sortAscending = false;
private void dataGridView_ColumnHeaderMouseClick ( object sender, DataGridViewCellMouseEventArgs e )
{
if ( sortAscending )
dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).ToList ( );
else
dataGridView.DataSource = list.OrderBy ( dataGridView.Columns [ e.ColumnIndex ].DataPropertyName ).Reverse ( ).ToList ( );
sortAscending = !sortAscending;
}
ponga esta línea en su formulario de Windows (en carga o mejor en un método público como "binddata"):
//
// bind the data and make the grid sortable
//
this.datagridview1.MakeSortable( myenumerablecollection );
Coloque este código en un archivo llamado DataGridViewExtensions.cs (o similar)
// MakeSortable extension.
// this will make any enumerable collection sortable on a datagrid view.
//
// BEGIN MAKESORTABLE - Mark A. Lloyd
//
// Enables sort on all cols of a DatagridView
//
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Forms;
public static class DataGridViewExtensions
{
public static void MakeSortable<T>(
this DataGridView dataGridView,
IEnumerable<T> dataSource,
SortOrder defaultSort = SortOrder.Ascending,
SortOrder initialSort = SortOrder.None)
{
var sortProviderDictionary = new Dictionary<int, Func<SortOrder, IEnumerable<T>>>();
var previousSortOrderDictionary = new Dictionary<int, SortOrder>();
var itemType = typeof(T);
dataGridView.DataSource = dataSource;
foreach (DataGridViewColumn c in dataGridView.Columns)
{
object Provider(T info) => itemType.GetProperty(c.Name)?.GetValue(info);
sortProviderDictionary[c.Index] = so => so != defaultSort ?
dataSource.OrderByDescending<T, object>(Provider) :
dataSource.OrderBy<T,object>(Provider);
previousSortOrderDictionary[c.Index] = initialSort;
}
async Task DoSort(int index)
{
switch (previousSortOrderDictionary[index])
{
case SortOrder.Ascending:
previousSortOrderDictionary[index] = SortOrder.Descending;
break;
case SortOrder.None:
case SortOrder.Descending:
previousSortOrderDictionary[index] = SortOrder.Ascending;
break;
default:
throw new ArgumentOutOfRangeException();
}
IEnumerable<T> sorted = null;
dataGridView.Cursor = Cursors.WaitCursor;
dataGridView.Enabled = false;
await Task.Run(() => sorted = sortProviderDictionary[index](previousSortOrderDictionary[index]).ToList());
dataGridView.DataSource = sorted;
dataGridView.Enabled = true;
dataGridView.Cursor = Cursors.Default;
}
dataGridView.ColumnHeaderMouseClick+= (object sender, DataGridViewCellMouseEventArgs e) => DoSort(index: e.ColumnIndex);
}
}
su cuadrícula de datos debe estar vinculada a una lista ordenable en primer lugar.
Crea este controlador de eventos:
void MakeColumnsSortable_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
//Add this as an event on DataBindingComplete
DataGridView dataGridView = sender as DataGridView;
if (dataGridView == null)
{
var ex = new InvalidOperationException("This event is for a DataGridView type senders only.");
ex.Data.Add("Sender type", sender.GetType().Name);
throw ex;
}
foreach (DataGridViewColumn column in dataGridView.Columns)
column.SortMode = DataGridViewColumnSortMode.Automatic;
}
Y inicializa el evento de cada una de tus datragrids de la siguiente manera:
dataGridView1.DataBindingComplete += MakeColumnsSortable_DataBindingComplete;
hay una solución bastante simple cuando se utiliza Entity Framework (versión 6 en este caso). No estoy seguro, pero parece que el método ObservableCollectionExtensions.ToBindingList<T>
devuelve la implementación de la lista de enlaces ordenables . No he encontrado el código fuente para confirmar esta suposición, pero el objeto que regresa de este método funciona muy bien con DataGridView
especialmente al ordenar las columnas haciendo clic en sus encabezados.
El código es muy simple y se basa únicamente en las clases .net y entity framework:
using System.Data.Entity;
IEnumerable<Item> items = MethodCreatingItems();
var observableItems = new System.Collections.ObjectModel.ObservableCollection<Item>(items);
System.ComponentModel.BindingList<Item> source = observableItems.ToBindingList();
MyDataGridView.DataSource = source;