Agrupación y ordenación en Xceed DataGrid para WPF

Esta semana vamos a echar un vistazo rápido a Agrupar y Ordenar en el DataGrid para WPF.

Más información Xceed DataGrid para WPF

Esta semana vamos a echar un vistazo rápido a Agrupar y Ordenar en el DataGrid para WPF.

Agrupación en tiempo de ejecución

Por defecto, cuando un DataGridControl contiene un HierarhicalGroupByControl en su sección de cabeceras fijas. El control de grupo por proporciona una vista condensada de los niveles de grupo y permite a los usuarios finales modificar las descripciones de grupo aplicadas a una rejilla.

Cada nivel de grupo está representado por un HierarchicalGroupByItem que se pueden utilizar para cambiar el orden de los grupos, ordenar los elementos de datos o eliminar los grupos por completo. Si un ColumnManagerRow está presente en una cuadrícula (independientemente de su ubicación), sus celdas (ColumnManagerCell) puede arrastrarse al control group-by para crear un nivel de grupo adicional.

Configuración de descripciones de grupos en la vista de colecciones

Los elementos de datos pueden agruparse añadiendo PropertyGroupDescription objetos o DataGridGroupDescription (recomendado) a los objetos DescripcionesGrupo propiedad del DataGridCollectionViewSource o DataGridCollectionView a la que está vinculada una cuadrícula.

En el siguiente ejemplo, agrupamos los pedidos por país y ciudad de envío:

<Grid xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
	<Grid.Resources>
		<xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
						   Source="{Binding Source={x:Static Application.Current},Path=Orders}">
			<xcdg:DataGridCollectionViewSource.GroupDescriptions>
				<xcdg:DataGridGroupDescription PropertyName="ShipCountry"/>
				<xcdg:DataGridGroupDescription PropertyName="ShipCity"/>
			</xcdg:DataGridCollectionViewSource.GroupDescriptions>
		</xcdg:DataGridCollectionViewSource>
	</Grid.Resources>

	<xcdg:DataGridControl x:Name="OrdersGrid"
			      ItemsSource="{Binding Source={StaticResource cvs_orders}}">
	</xcdg:DataGridControl>
</Grid>

Nota: Del mismo modo, también es posible hacer lo mismo con un DataGridDetailDescription, y/o directamente a través de la propiedad Items y especificando el nombre de campo de la columna por cuyos valores agrupar. Cada DataGridGroupDescription que se añade a esta colección representa las características de un nivel de grupo en una cuadrícula.

Agrupación personalizada

También es posible crear una descripción de grupo personalizada derivando de la función DataGridGroupDescription y sobreescribiendo la clase GroupNameFromItem método. Una vez implementado, un SortComparer se le puede asignar.

En primer lugar, tenemos que crear nuestra descripción de grupo personalizada:

public class AlphabeticalGroupDescription : DataGridGroupDescription
{
	public AlphabeticalGroupDescription()
		: base()
	{
	}
	public AlphabeticalGroupDescription( string propertyName )
		: base( propertyName )
	{
	}

	public override object GroupNameFromItem( object item, int level, System.Globalization.CultureInfo culture )
	{
		object value = base.GroupNameFromItem( item, level, culture );
		try
		{
			string content = Convert.ToString( value );
			value = content.ToUpper().Substring( 0, 1 );
		}
		catch( InvalidCastException )
		{
		}
		return value;
	}
}

A continuación, lo añadimos a nuestro DataGridCollectionViewSource:

<Grid.Resources>
	<local:ConsonantVowelComparer x:Key="consonantVowelComparer"/>
	<xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
					   Source="{Binding Source={x:Static Application.Current}, Path=Orders}">
		<xcdg:DataGridCollectionViewSource.GroupDescriptions>
			<local:AlphabeticalGroupDescription PropertyName="ShipCountry"
							    SortComparer="{StaticResource consonantVowelComparer}"/>
		</xcdg:DataGridCollectionViewSource.GroupDescriptions>
	</xcdg:DataGridCollectionViewSource>
</Grid.Resources>

Prevención de la agrupación

Es posible impedir que el usuario pueda modificar los grupos, de forma que los grupos que aplique no puedan ser eliminados ni añadidos. Esto se consigue utilizando la opción AllowGroupingModification de la propiedad GroupByControl.

Dado que estamos redefiniendo las cabeceras fijas, necesitamos establecer UseDefaultHeadersFooters a false y añadir manualmente las cabeceras que queramos.

Por ejemplo:

<xcdg:DataGridControl x:Name="OrdersGrid"
		      ItemsSource="{Binding Source={StaticResource cvs_orders}}">
	<xcdg:DataGridControl.View>
		<xcdg:TableView UseDefaultHeadersFooters="False">
			<xcdg:TableView.FixedHeaders>
				<DataTemplate>
					<xcdg:GroupByControl AllowGroupingModification="False" />
				</DataTemplate>
				<DataTemplate>
					<xcdg:ColumnManagerRow />
				</DataTemplate>
			</xcdg:TableView.FixedHeaders>
		</xcdg:TableView>
	</xcdg:DataGridControl.View>
</xcdg:DataGridControl>

Clasificación en tiempo de ejecución

Cuando un DataGridControl contiene por defecto un ColumnManagerRow en su sección de cabeceras fijas que contiene un ColumnManagerCell para cada columna de una cuadrícula. El contenido de una o varias columnas puede ordenarse haciendo clic en la columna correspondiente. ColumnManagerCell.

Por defecto, al hacer clic una vez se ordenarán los valores de la columna en sentido ascendente, al hacer clic dos veces se ordenarán en sentido descendente, mientras que al hacer clic tres veces se eliminará cualquier ordenación que se haya aplicado a los valores de la columna. Para ordenar los valores de varias columnas, mantenga pulsada la tecla MAYÚS mientras hace clic en una columna. ColumnManagerCell. El ciclo sort-direction puede modificarse proporcionando a una columna un nuevo SortDirectionCycle o manejando la colección SortDirectionChanging evento.

Establecer descripciones de ordenación en la vista de colección

Los elementos de datos pueden ordenarse añadiendo OrdenarDescripción objetos a la OrdenarDescripciones propiedad del DataGridCollectionViewSource o DataGridCollectionView a la que está vinculada una cuadrícula.

En el siguiente ejemplo, agrupamos los pedidos por país y ciudad de envío:

<Grid xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
      xmlns:xcdg="http://schemas.xceed.com/wpf/xaml/datagrid">
	<Grid.Resources>
		<xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
						   Source="{Binding Source={x:Static Application.Current}, Path=Orders}">
			<xcdg:DataGridCollectionViewSource.SortDescriptions>
				<scm:SortDescription PropertyName="ShipCountry"
						     Direction="Ascending"/>
			</xcdg:DataGridCollectionViewSource.SortDescriptions>
		</xcdg:DataGridCollectionViewSource>
	</Grid.Resources>

	<xcdg:DataGridControl x:Name="OrdersGrid"
			      ItemsSource="{Binding Source={StaticResource cvs_orders}}">
		<xcdg:DataGridControl.Columns>
			<xcdg:Column FieldName="ShipCountry" VisiblePosition="0"/>
		</xcdg:DataGridControl.Columns>
	</xcdg:DataGridControl>
</Grid>

También es posible hacerlo directamente a través de la propiedad Items, y especificando el nombre de campo de la columna por cuyos valores ordenar así como la dirección en la que se deben ordenar dichos valores.

Clasificación personalizada

Además de la ordenación basada en tipos por defecto, también es posible aplicar una ordenación personalizada proporcionando una variable IComparer a la SortComparer de una o varias propiedades de elemento definidas en el DataGridCollectionView o DataGridCollectionViewSource al que está vinculada una rejilla El comparador se utilizará siempre que se ordenen los valores de la columna correspondiente a la propiedad del elemento, por ejemplo, al hacer clic en la cabecera de la columna.

En primer lugar, tenemos que crear nuestro IComparer:

public class AddressComparer: IComparer
{
	public AddressComparer()
	{
	}
	int IComparer.Compare( object x, object y )
	{
		string stringX = ( string )x;
		string stringY = ( string )y;
		const string digits = "0123456789";
		if( ( digits.IndexOf( stringX[ 0 ] ) >= 0 ) && ( digits.IndexOf( stringY[ 0 ] ) >= 0 ) )
		{
			int index = 0;
			System.Text.StringBuilder xNumber = new System.Text.StringBuilder();
			while( ( index < stringX.Length ) && ( digits.IndexOf( stringX[ index ] ) >= 0 ) )
			{
				xNumber.Append( stringX[ index ] );
				index++;
			}
			index = 0;
			System.Text.StringBuilder yNumber = new System.Text.StringBuilder();
			while( ( index < stringY.Length ) && ( digits.IndexOf( stringY[ index ] ) >= 0 ) )
			{
				yNumber.Append( stringY[ index ] );
				index++;
			}
			long xValue = long.Parse( xNumber.ToString() );
			long yValue = long.Parse( yNumber.ToString() );
			if( xValue > yValue )
				return 1;
			if( xValue < yValue )
				return -1;
			return stringX.CompareTo( stringY );
		}
		else
		{
			return stringX.CompareTo( stringY );
		}
	}
}

A continuación, lo añadimos a nuestro DataGridCollectionViewSource:

<Grid.Resources>
	<local:AddressComparer x:Key="addressComparer"/>
	<xcdg:DataGridCollectionViewSource x:Key="cvs_orders"
					   Source="{Binding Source={x:Static Application.Current}, Path=Orders}"
					   AutoCreateItemProperties="False">
		<xcdg:DataGridCollectionViewSource.ItemProperties>
			<xcdg:DataGridItemProperty Name="ShipCountry" />
			<xcdg:DataGridItemProperty Name="ShipCity" />
			<xcdg:DataGridItemProperty Name="ShipAddress"
						   SortComparer="{StaticResource addressComparer}"/>
			<xcdg:DataGridItemProperty Name="ShipVia" />
		</xcdg:DataGridCollectionViewSource.ItemProperties>
	</xcdg:DataGridCollectionViewSource>
</Grid.Resources>

Evitar la clasificación

Es posible impedir que el usuario pueda ordenar las columnas, de forma que cualquier ordenación que aplique no pueda ser eliminada ni modificada. Esto se consigue utilizando la función PermitirOrdenar disponible en GroupByControl y ColumnManagerRow.

Dado que estamos redefiniendo las cabeceras fijas, necesitamos establecer UseDefaultHeadersFooters a false y añadir manualmente las cabeceras que queramos.

Por ejemplo:

<xcdg:DataGridControl x:Name="OrdersGrid"
		      ItemsSource="{Binding Source={StaticResource cvs_orders}}">
	<xcdg:DataGridControl.View>
		<xcdg:TableView UseDefaultHeadersFooters="False">
			<xcdg:TableView.FixedHeaders>
				<DataTemplate>
					<xcdg:GroupByControl AllowSort="False" />
				</DataTemplate>
				<DataTemplate>
					<xcdg:ColumnManagerRow AllowSort="False" />
				</DataTemplate>
			</xcdg:TableView.FixedHeaders>
		</xcdg:TableView>
	</xcdg:DataGridControl.View>
</xcdg:DataGridControl>

Para más información, consulte el documentación.