miércoles, 14 de marzo de 2012

Silverlight ControlGridHelper–Objeto que permite redistribuir la información de la Grid, cuando hay elementos con visibilidad colapsada.

 

Como parte de un desarrollo, es necesario mostrar o no información, dependiendo de la opción seleccionada por el usuario. Ahora, para la ubicación de la información en la página XAML, se utilizó el control Panel Grid.

Como se ve en el siguiente ejemplo:

ControlGridHelper1

Si dinámicamente, se debe ocultar el botón 11, en la pantalla, simplemente queda el espacio en blanco, como se muestra a continuación:

ControlGridHelper2

El ControlGridHelper, permite redistribuir los controles restantes, para ocupar los espacios vacíos. Por ejemplo, en el escenario mostrado, podemos indicarle al ControlGridHelper que nos reacomode los controles por fila, así:

ControlGridHelper.Instance.ReacomodarControlesGrid(LayoutRoot,false);

Y el resultado es este:


ControlGridHelper3


Es decir, se ubica en la celda con el espacio en blanco y desplaza los controles por la fila hacia la izquierda:


ControlGridHelper4





También se puede lograr, el reacomodo, por columnas así:


Tenemos la situación original:


ControlGridHelper1


Ahora, supongamos que el botón 2, queda oculto y que el reacomodo se hace por columnas. Eso lo indicamos de esta forma:

ControlGridHelper.Instance.ReacomodarControlesGrid(LayoutRoot,true);

Y el resultado es este:


ControlGridHelper5


Es decir, se ubica en la celda con el espacio en blanco y desplaza los controles por la columna hacia arriba:


ControlGridHelper6



Utilizar el objeto ControlGridHelper, es muy sencillo, solo es llamar a su método ReacomodarControlesGrid y pasarle como parámetros: la Grid, cuyos controles se reacomodarán  y la indicación de si el reacomodo será por filas o por columnas ( tu decides).


El propósito del objeto ControlGridHelper es ayudar a reacomodar la información en la Grid, para que la presentación de ésta sea más agradable, en la situación ilustrada de ocultación dinámica de controles en el Grid.


Espero que les sirva, aquí les dejo el código:

public sealed class ControlGridHelper
{
/// <summary>
///
Contiene información adicional de ayuda, para la manipulación de la
/// información en la grid.
/// </summary>
private class GridHelper
{
/// <summary>
///
Almacena el identificador de la fila
/// </summary>
private int _fila;
/// <summary>
///
Almacena el identificador de la columna
/// </summary>
private int _col;

/// <summary>
///
Almacena el número de controles eliminados en la fila
/// </summary>
private int _numeroControlesEliminadosFila;
/// <summary>
///
Almacena el número de controles eliminados en la columna
/// </summary>
private int _numeroControlesEliminadosCol;
/// <summary>
///
Permite obtener o asignar el identificador de la fila
/// </summary>
public int Fila
{
get
{
return _fila;
}
set
{
_fila = value;
}
}
/// <summary>
///
Permite obtener o asignar el identificador de la columna
/// </summary>
public int Columna
{
get
{
return _col;
}
set
{
_col = value;
}
}
/// <summary>
///
Permite obtener o asignar el número de controles eliminados de la
/// fila
/// </summary>
public int NumeroControlesEliminadosFila
{
get
{
return _numeroControlesEliminadosFila;
}
set
{
_numeroControlesEliminadosFila = value;
}
}
/// <summary>
///
Permite obtener o asignar el número de controles eliminados de la
/// columna
/// </summary>
public int NumeroControlesEliminadosCol
{
get
{
return _numeroControlesEliminadosCol;
}
set
{
_numeroControlesEliminadosCol = value;
}
}
/// <summary>
///
Incrementa el número de controles eliminados en la
/// fila
/// </summary>
/// <param name="fila">
Identificador de la fila</param>
public void IncrementarNumeroControlesEliminadosFila(int fila)
{
if (_fila == fila)
{
_numeroControlesEliminadosFila++;
}
}
/// <summary>
///
Incrementa el número de controles eliminados en la
/// columna
/// </summary>
/// <param name="col">
Identificador de la columna</param>
public void IncrementarNumeroControlesEliminadosCol(int col)
{
if (_col == col)
{
_numeroControlesEliminadosCol++;
}
}
};

/// <summary>
///
Instancia privada para la implementación del patrón Singleton
/// </summary>
private static readonly ControlGridHelper instance = new ControlGridHelper();

/// <summary>
///
Constructor privado, usada por la implementación del patrón Singleton
/// </summary>
private ControlGridHelper() { }

/// <summary>
///
Instancia del Helper, para poder usar los métodos
/// </summary>
public static ControlGridHelper Instance
{
get
{
return instance;
}
}


/// <summary>
///
Reacomoda los controles en un control Grid, ya sea por columnas o por filas.
/// </summary>
/// <param name="gridControl">
Es el control Grid</param>
/// <param name="porColumna">
Indica si el reacomodo se hará por columnas o por filas</param>
public void ReacomodarControlesGrid(Grid gridControl, bool porColumna = true)
{
int col = -1;
int fila = -1;
//Los controles que se encuentran con visibilidad Collapset al
//final son eliminados para evitar generacion de excepciones.
List<object> controlesARemover = new List<object>();
List<GridHelper> listaGridHelper = CargarListaGridHelper(gridControl);
for (int contador = 0; contador < gridControl.Children.Count; contador++)
{
var control = gridControl.Children[contador];

if (control.Visibility == Visibility.Collapsed)
{
fila = Convert.ToInt32(control.GetValue(Grid.RowProperty));
col = Convert.ToInt32(control.GetValue(Grid.ColumnProperty));
//Se agrega el control a la lista de los que se eliminarán.
controlesARemover.Add(control);
if (porColumna)
{
//Se reacomoda la información de la columna
ReacomodarControlesPorColumna(gridControl, col, fila);
}
else
{
//Se reacomoda la información de la fila
ReacomodarControlesPorFila(gridControl, col, fila);
}
}
}

//Se remueven los controles, por si se vuelve a ejecutar el código no
//se produzca ningún error.
foreach (var control in controlesARemover)
{
gridControl.Children.Remove((UIElement)control);
}

if (porColumna)
{
EliminarColumnasSinControles(gridControl, listaGridHelper);
}
else
{
//Es por fila
EliminarFilasSinControles(gridControl, listaGridHelper);
}

//Pueden quedar filas sin controles

for (int contador = gridControl.RowDefinitions.Count - 1; contador >= 0; contador--)
{
if (!ValidarFilaConControles(gridControl, contador))
{
gridControl.RowDefinitions.RemoveAt(contador);
}
}
//Pueden quedar columnas sin controles
for (int contador = gridControl.ColumnDefinitions.Count - 1; contador >= 0; contador--)
{
if (!ValidarColumnaConControles(gridControl, contador))
{
gridControl.ColumnDefinitions.RemoveAt(contador);
}
}
}

/// <summary>
///
Verifica si una fila tiene o no controles
/// </summary>
/// <param name="gridControl">
Es el control Grid</param>
/// <param name="fila">
Es la fila que se verifica</param>
/// <returns>
True o False dependiendo de lo encontrado</returns>
private bool ValidarFilaConControles(Grid gridControl, int fila)
{
for (int contador = 0; contador < gridControl.Children.Count; contador++)
{
var control = gridControl.Children[contador];
if (fila == Convert.ToInt32(control.GetValue(Grid.RowProperty)))
{
return true;
}

}
return false;
}
/// <summary>
///
Verifica si una columna tiene o no controles
/// </summary>
/// <param name="gridControl">
Es el control Grid</param>
/// <param name="col">
Es la columna que se verifica</param>
/// <returns>
True o False dependiendo de lo encontrado</returns>
private bool ValidarColumnaConControles(Grid gridControl, int col)
{
for (int contador = 0; contador < gridControl.Children.Count; contador++)
{
var control = gridControl.Children[contador];
if (col == Convert.ToInt32(control.GetValue(Grid.ColumnProperty)))
{
return true;
}

}
return false;
}

/// <summary>
///
Carga el listado de objetos GridHelper con la información apropiada
/// </summary>
/// <param name="gridControl">
Es el control Grid</param>
/// <returns>
Lista de objetos GridHelper</returns>
private List<GridHelper> CargarListaGridHelper(Grid gridControl)
{
int col = -1;
int fila = -1;
List<GridHelper> listaGridHelper = new List<GridHelper>();
for (int contador = 0; contador < gridControl.Children.Count; contador++)
{
var control = gridControl.Children[contador];
col = Convert.ToInt32(control.GetValue(Grid.ColumnProperty));
if (listaGridHelper.Where(item => item.Columna == col).ToList().Count == 0)
{
listaGridHelper.Add(new GridHelper() { Columna = col });
}
fila = Convert.ToInt32(control.GetValue(Grid.RowProperty));
if (listaGridHelper.Where(item => item.Fila == fila).ToList().Count == 0)
{
listaGridHelper.Add(new GridHelper() { Fila = fila });
}


if (control.Visibility == Visibility.Collapsed)
{
fila = Convert.ToInt32(control.GetValue(Grid.RowProperty));
col = Convert.ToInt32(control.GetValue(Grid.ColumnProperty));
//Se incrementa el número de controles que se eliminan de la
//columna
listaGridHelper.Where(item => item.Columna == col).FirstOrDefault().
IncrementarNumeroControlesEliminadosCol(col);

//Se incrementa el número de controles que se eliminan de la
//fila
listaGridHelper.Where(item => item.Fila == fila).FirstOrDefault().
IncrementarNumeroControlesEliminadosFila(fila);
}
}

return listaGridHelper;
}

/// <summary>.
/// Elimina las columnas que quedan sin controles
/// </summary>
/// <param name="gridControl">
Es el control grid</param>
/// <param name="listaGridHelper">
Es la lista de información de ayuda de la Grid</param>
private void EliminarColumnasSinControles(Grid gridControl, List<GridHelper> listaGridHelper)
{
foreach (var item in listaGridHelper)
{

if (item.NumeroControlesEliminadosCol == gridControl.RowDefinitions.Count)
{
if (item.Columna < gridControl.ColumnDefinitions.Count - 1)
{
//Se mueven los controles de las otras columnas hacia la
//que se elimina
DesplazarControlesUnaColumna(gridControl, item.Columna);
}
gridControl.ColumnDefinitions.RemoveAt(item.Columna);

}

}

}
/// <summary>.
/// Elimina las filas que quedan sin controles
/// </summary>
/// <param name="gridControl">
Es el control grid</param>
/// <param name="listaGridHelper">
Es la lista de información de ayuda de la Grid</param>
private void EliminarFilasSinControles(Grid gridControl, List<GridHelper> listaGridHelper)
{
foreach (var item in listaGridHelper)
{
if (item.NumeroControlesEliminadosFila == gridControl.ColumnDefinitions.Count)
{
if (item.Fila < gridControl.RowDefinitions.Count - 1)
{
//Se mueven los controles de las otras filas hacia la
//que se elimina
DesplazarControlesUnaFila(gridControl, item.Fila);
}
gridControl.RowDefinitions.RemoveAt(item.Fila);

}
}
}
/// <summary>
///
Mueve los controles recursivamente hacia la columna que se encuentra
/// vacía. Asegurandose, de esta forma, que la columna que quede sin controles
/// sea la última.
/// </summary>
/// <param name="gridControl">
Control Grid</param>
/// <param name="col">
Columna que se encuentra sin controles</param>
private void DesplazarControlesUnaColumna(Grid gridControl, int col)
{
foreach (var control in gridControl.Children)
{
if (Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) > col)
{
control.SetValue(Grid.ColumnProperty, Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) - 1);
}
}
}

/// <summary>
///
Mueve los controles recursivamente hacia la fila que se encuentra
/// vacía. Asegurandose, de esta forma, que la fila que quede sin controles
/// sea la última.
/// </summary>
/// <param name="gridControl">
Control Grid</param>
/// <param name="fila">
Fila que se encuentra sin controles</param>
private void DesplazarControlesUnaFila(Grid gridControl, int fila)
{
foreach (var control in gridControl.Children)
{
if (Convert.ToInt32(control.GetValue(Grid.RowProperty)) > fila)
{
control.SetValue(Grid.RowProperty, Convert.ToInt32(control.GetValue(Grid.RowProperty)) - 1);
}
}
}
/// <summary>
///
Mueve reiteradamente los controles de una columna, hacia arriba,
/// asegurandose que ocupen la posición que ocupaba un control con
/// visibilidad Collapsed. De esta forma, se asegura, que la última
/// fila de la columna queda sin controles.
/// </summary>
/// <param name="gridControl">
Control Grid</param>
/// <param name="col">
Columna que posee el control de visibilidad Collapsed</param>
/// <param name="fila">
Fila que posee el control de visibilidad Collapsed</param>
private void ReacomodarControlesPorColumna(Grid gridControl, int col, int fila)
{
foreach (var control in gridControl.Children)
{
if (Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) == col &&
Convert.ToInt32(control.GetValue(Grid.RowProperty)) > fila)
{
control.SetValue(Grid.RowProperty, Convert.ToInt32(control.GetValue(Grid.RowProperty)) - 1);
}
}
}

/// <summary>
///
Mueve reiteradamente los controles de una fila, hacia la izquierda,
/// asegurandose que ocupen la posición que ocupaba un control con
/// visibilidad Collapsed. De esta forma, se asegura, que la última
/// columna de la fila queda sin controles.
/// </summary>
/// <param name="gridControl">
Control Grid</param>
/// <param name="col">
Columna que posee el control de visibilidad Collapsed</param>
/// <param name="fila">
Fila que posee el control de visibilidad Collapsed</param>
private void ReacomodarControlesPorFila(Grid gridControl, int col, int fila)
{
foreach (var control in gridControl.Children)
{
if (Convert.ToInt32(control.GetValue(Grid.RowProperty)) == fila &&
Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) > col)
{
control.SetValue(Grid.ColumnProperty, Convert.ToInt32(control.GetValue(Grid.ColumnProperty)) - 1);
}
}
}


}