Uma das coisas que mais me irrita fazer é a
Graphical User Interface (
GUI), perde-se imenso tempo com detalhes da treta e acabamos por não aprender nada de novo. Isto alcança o seu auge quando falamos de
DataGrid, vendido como sendo a melhor coisa do mundo, a verdade é que é muito bom sim para demos rápidas, agora quando se quer começar a personalizar começa a dar mais trabalho que benefícios.
Estava aqui a trabalhar numa
DataGrid em
WPF quando me foi pedido que a cor de cada
row fosse condicionada a uma propriedade do objecto que estava a ser
bind. Parece simples...pois não é nada trivial e perdi à volta de 3h em pesquisas na
internet e a implementar vários exemplos até que cheguei a uma solução que me agradou minimamente e era funcional.
Para o exemplo vamos considerar os seguintes pontos:
- A nossa DataGrid tem o nome de dGrid;
- O tipo do objecto que é bind a cada row é Register;
- A propriedade do objecto que vai ser usada para condicionar a cor da row é a propriedade LK;
Os 2 principais contratempos que tive foram a altura em que podia afectar a cor da
row e o facto de não poder afectar a cor da
row, mas sim das células pois a cor das células sobrepõe-se à cor da
row. Em relação à altura em que podia afectar a cor das células, em
WPF só temos garantia que todos os filhos da janela estão prontos no evento
Loaded da janela, logo tenho de ter um
listener neste evento que no meu caso é o método
WindowLoaded. Seguindo todos estes pressupostos o código seguinte exemplifica a solução a que cheguei.
private void WindowLoaded(object sender, RoutedEventArgs e){
UpdateRowColor();
}
private void UpdateRowColor(){
for (int i = 0; i < dGrid.Items.Count; ++i){
DataGridRow row = GetRow(dGrid, i);
if (row.Item is Register){
Register registry = (Register)row.Item;
for (int j = 0; j < dGrid.Columns.Count; ++j){
if (registry.LK == "O")
GetCell(dGrid, row, j).Background = Brushes.Green;
else
GetCell(dGrid, row, j).Background = Brushes.Red;
}
}
}
}
private DataGridRow GetRow(DataGrid dataGrid, int index){
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(index);
if (row == null){
dataGrid.ScrollIntoView(dataGrid.Items[index]);
dataGrid.UpdateLayout();
row = (DataGridRow)dataGrid.ItemContainerGenerator.ContainerFromIndex(index);
}
return row;
}
private DataGridCell GetCell(DataGrid dataGrid, DataGridRow rowContainer, int column)
{
if (rowContainer != null){
DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(rowContainer);
// try to get the cell but it may possibly be virtualized
DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
if (cell == null){
// now try to bring into view and retreive the cell
dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
}
return cell;
}
return null;
}
private T GetVisualChild<T>(Visual parent) where T : Visual{
T child = default(T);
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); ++i){
Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T;
if (child == null)
child = GetVisualChild<T>(v);
if (child != null)
break;
}
return child;
}