Reputation: 489
I have a class Ro
that has 4 fields (2 names and 2 colors)
public class Ro
{
public string c1 { get; set; }
public SolidColorBrush c1Color { get; set; }
public string c2 { get; set; }
public SolidColorBrush c2Color { get; set; }
}
I have created a List of Ro objects
List<Ro> data = new List<Ro>();
data.Add(new Ro()
{
c1 = "7B",
c1Color = Brushes.Green,
c2 = "",
c2Color = Brushes.White
});
data.Add(new Ro()
{
c1 = "Jot",
c1Color = Brushes.Green,
c2 = "",
c2Color = Brushes.Black
});
data.Add(new Ro()
{
c1 = "Nav",
c1Color = Brushes.White,
c2 = "",
c2Color = Brushes.Orange
});
Now I want to use this List to populate a wpf DataGridView
assigning the color to each cell depending on current field of object when looping the list
To do so I created a method that will create ControlTemplate for each cell:
public ControlTemplate CellTemplate(string text, SolidColorBrush color)
{
ControlTemplate template = new ControlTemplate();
template.VisualTree = new FrameworkElementFactory(typeof(TextBlock));
template.VisualTree.SetValue(TextBlock.TextProperty, text);
template.VisualTree.SetValue(TextBlock.BackgroundProperty, color);
template.VisualTree.SetValue(TextBlock.TextAlignmentProperty, TextAlignment.Center);
template.VisualTree.SetValue(TextBlock.FontWeightProperty, FontWeights.Bold);
if (color == Brushes.White)
template.VisualTree.SetValue(TextBlock.ForegroundProperty, Brushes.Black);
else
template.VisualTree.SetValue(TextBlock.ForegroundProperty, Brushes.White);
return template;
}
and also I created a dataColumn c1
dataGrid1.Columns.Add(
new DataGridTextColumn
{ Header = "c1" });
finally in a foreach loop I create the cells with styles
foreach (Ro me in data)
{
DataGridCell cell0 = new DataGridCell { Template = CellTemplate(me.c1,me.c1Color) };
dataGrid1.Items.Add(cell0);
}
so far so good, however when I add the second column and try to apply the same idea like
dataGrid1.Columns.Add(
new DataGridTextColumn
{ Header = "c2" });
foreach (Ro me in data)
{
DataGridCell cell0 = new DataGridCell { Template = CellTemplate(me.c1,me.c1Color) };
dataGrid1.Items.Add(cell0);
DataGridCell cell1 = new DataGridCell { Template = CellTemplate(me.c2, me.c2Color) };
dataGrid1.Items.Add(cell1);
}
i get excepction:
System.ArgumentOutOfRangeException was unhandled on System.Windows.Media.VisualCollection.get_Item(Int32 index) on System.Windows.Controls.UIElementCollection.get_Item(Int32 index) on System.Windows.Controls.UIElementCollection.System.Collections.IList.get_Item(Int32 index) on System.Windows.Controls.DataGridCellsPanel.ArrangeOverride(Size arrangeSize) ...
if I have only one column in dgv I get:
I tried doing following, but got error, I do not know how to insert a particular cell in a particular column in dgv...
foreach (Ro me in data)
{
DataGridCell cell0 = new DataGridCell { Template = CellTemplate(me.c1, me.c1Color) };
DataGridCell cell1 = new DataGridCell { Template = CellTemplate(me.c2, me.c2Color) };
dataGrid1.Columns.Insert(0, cell0);
dataGrid1.Columns.Insert(1, cell0);
//dataGrid1.Items.Add(cell0);
//dataGrid1.Items.Add(cell1);
}
How can I add cells in a row programatically?
Upvotes: 0
Views: 626
Reputation: 27039
This is not possible without doing some gymnastics. Add your columns like this:
this.dataGrid.Columns.Add(
new DataGridTextColumn
{ Header = "c1", Binding = new Binding("c1") } );
this.dataGrid.Columns.Add(
new DataGridTextColumn
{ Header = "c2", Binding = new Binding("c2") });
this.dataGrid.LoadingRow += DataGrid_LoadingRow;
foreach (Ro me in data)
{
dataGrid.Items.Add(me);
}
See how the code bounds the C1
column to c1
property of your Ro
. See how the code also subscribes to the LoadingRow
event. Here is the handler for the row which calls the AlterRow
method asynchronously:
private void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => AlterRow(e)));
}
And here is the rest of the code which basically finds the cells in columns 0 and columns 1 for each row and then figures out the background property and sets it.
private void AlterRow(DataGridRowEventArgs e)
{
var cell = GetCell(dataGrid, e.Row, 0);
if (cell == null) return;
var item = e.Row.Item as Ro;
if (item == null) return;
cell.Background = item.c1Color;
cell = GetCell(dataGrid, e.Row, 1);
if (cell == null) return;
cell.Background = item.c2Color;
}
public static T GetVisualChild<T>(Visual parent) where T : Visual
{
T child = default(T);
int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < numVisuals; i++)
{
var v = (Visual)VisualTreeHelper.GetChild(parent, i);
child = v as T ?? GetVisualChild<T>(v);
if (child != null)
{
break;
}
}
return child;
}
public static DataGridCell GetCell(DataGrid host, DataGridRow row, int columnIndex)
{
if (row == null) return null;
var presenter = GetVisualChild<DataGridCellsPresenter>(row);
if (presenter == null) return null;
// try to get the cell but it may possibly be virtualized
var cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
if (cell == null)
{
// now try to bring into view and retreive the cell
host.ScrollIntoView(row, host.Columns[columnIndex]);
cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
}
return cell;
}
Some of the code was borrowed form here.
Upvotes: 1