Usage of a TextBlock is quite common in CellTemplates of Columns in a C1Flexgrid for WPF. There might a requirement of changing BackGround/ForeGround of C1FlexGrid rows on some event, say MouseHover. In this we will discuss just that. Consider a C1Flexgrid with three columns; "ID", "First Name" and "Last Name". "First Name" has a TextBlock as its CellTemplate; and XAML looks like this:
<c1:C1FlexGrid.Columns>
<c1:Column Binding="{Binding ID}" Header="ID" Width="50"/>
<c1:Column Binding="{Binding FName}" Header="First Name" Width="200">
<c1:Column.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding FName}"/>
</DataTemplate>
</c1:Column.CellTemplate>
</c1:Column>
<c1:Column Binding="{Binding LName}" Header="Last Name" Width="200"/>
</c1:C1FlexGrid.Columns>
</c1:C1FlexGrid>
Lets create a Person class for binding the grid.
public class Person : INotifyPropertyChanged
{
private int id;
private string fname;
private string lname;
public int ID
{
get { return id; }
set { id = value; NotifyPropertyChanged("ID"); }
}
public string FName
{
get { return fname; }
set { fname = value; NotifyPropertyChanged("FName"); }
}
public string LName
{
get { return lname; }
set { lname = value; NotifyPropertyChanged("LName"); }
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
#endregion
}
Following code will create a collection Person objects and bind it with C1FlexGrid.
List<Person> person = new List<Person>();
#region "Data"
person.Add(new Person() { ID = 1, FName = "Robert", LName = "Ludlum" });
person.Add(new Person() { ID = 2, FName = "Tom", LName = "Clancy" });
person.Add(new Person() { ID = 3, FName = "Mario", LName = "Puzo" });
person.Add(new Person() { ID = 4, FName = "Frederick", LName = "Forsyth" });
person.Add(new Person() { ID = 5, FName = "Alistair", LName = "Campbell" });
person.Add(new Person() { ID = 6, FName = "Paulo", LName = "Coelho" });
person.Add(new Person() { ID = 7, FName = "William", LName = "Shakespeare" });
person.Add(new Person() { ID = 8, FName = "Anna", LName = "Hathaway" });
person.Add(new Person() { ID = 9, FName = "Dan", LName = "Brown" });
person.Add(new Person() { ID = 10, FName = "Charles", LName = "Dickens" });
#endregion
this.c1FlexGrid1.ItemsSource = person;
After binding our grid looks like : Now, all we need is to listen to MouseMove event of the grid and use HitTestInfo class to detect the Row indices/CellType and paint the BackGround/ForeGround as per our choice. Certainly, AlternatingRowBackground needs to be kept into consideration too; because when Mouse pointer moves to a different row, then the current row needs to be painted with the same Brush, as it was earlier. The following snippet should do the job:
SolidColorBrush evenRowColor; //Odd RowBackground
SolidColorBrush oddRowColor; //Even RowBackGround
SolidColorBrush mouseHover = new SolidColorBrush(Colors.Red); //MouseHover BackGround
//Capture Odd/even rows' backcolor
evenRowColor = (SolidColorBrush)this.c1FlexGrid1.Rows[0].Background;
oddRowColor = (SolidColorBrush)this.c1FlexGrid1.Rows[1].Background;
int currentRow = -1;
void c1FlexGrid1_MouseMove(object sender, MouseEventArgs e)
{
C1.WPF.FlexGrid.HitTestInfo ht = this.c1FlexGrid1.HitTest(e);
if (ht.CellType == C1.WPF.FlexGrid.CellType.Cell)
{
if (currentRow != ht.Row)
{
//Exclude Column Headers
if (currentRow != -1)
//Verify odd/even row
if (currentRow % 2 == 0)
this.c1FlexGrid1.Rows[currentRow].Background = evenRowColor;
else
this.c1FlexGrid1.Rows[currentRow].Background = oddRowColor;
//Get Current Row Index
currentRow = ht.Row;
//Set Current Row BackColor
this.c1FlexGrid1.Rows[currentRow].Background = mouseHover;
}
}
}
With the above code, our grid looks like : As shown in the image, the BackGround of the "First Name" column is not changed. The reason for this is that this particular column uses a TextBlock in its CellTemplate and the TextBlock's BackGround isn't getting set. For setting the background of CellTemplate column, we will use CellFactory class. The C1Flexgrid has a CellFactory class that is responsible for creating every cell shown on the grid.
//Customized CellFactory
public class MyCellFactory : CellFactory
{
C1FlexGrid parentGrid;
int crIndex = -1;
public override FrameworkElement CreateCell(C1FlexGrid grid, CellType cellType, CellRange range)
{
//if (cellType == CellType.Cell)
// Console.WriteLine(range.Row.ToString());
if (parentGrid == null)
{
parentGrid = grid;
}
if (cellType == CellType.Cell)
{
var obj = base.CreateCell(grid, cellType, range);
if (range.Column != 1)
if (crIndex != -1)
{
if (range.Row != crIndex)
{
if (range.Row % 2 == 0)
(obj as Border).Background = parentGrid.AlternatingRowBackground;
else
(obj as Border).Background = parentGrid.RowBackground;
((obj as Border).Child as TextBlock).Foreground = parentGrid.Foreground;
}
else
{
(obj as Border).Background = new SolidColorBrush(Colors.Pink);
((obj as Border).Child as TextBlock).Foreground = new SolidColorBrush(Colors.Red);
}
}
if (range.Column == 1)
{
if (crIndex > -1)
{
if (range.Row == crIndex)
{
(obj as Border).Background = new SolidColorBrush(Colors.Pink);
((obj as Border).Child as TextBlock).Foreground = new SolidColorBrush(Colors.Red);
}
}
}
if (obj.GetType() == typeof(Border))
obj.PreviewMouseMove += new MouseEventHandler(obj_PreviewMouseMove);
return obj;
}
return base.CreateCell(grid, cellType, range);
}
int rowIndex;
void obj_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (sender.GetType() == typeof(Border))
rowIndex = Grid.GetRow((sender as Border));
else
rowIndex = Grid.GetRow(((sender as TextBlock).Parent as Border));
crIndex = rowIndex;
if (parentGrid != null)
{
rowIndex = crIndex;
this.parentGrid.Rows[rowIndex].Background = new SolidColorBrush(Colors.Red);
this.parentGrid.Rows[rowIndex].Foreground = new SolidColorBrush(Colors.LightGoldenrodYellow);
}
}
}
All that is left, is to assign this CellFactory's object to C1FlexGrid's CellFactory property.
this.c1FlexGrid2.CellFactory = new MyCellFactory();
Now when you'll hover mouse over the flexgid, the Backgroudn and Foreground gets applied as shown in the image below. Observe, both ForeGround and BackGround getting changed on MouseHover. In the sample available for download, I used two C1WpfFlexGrids. First, demonstrating the successful attempt to change Row's BackGround, excluding the column with TextBlock in CellTemplate, in MouseHover. Second, demonstrating row's BackGround getting changed, including the column with TextBlock in CellTemplate, using Custom CellFactory. Refer to the attached sample for the detailed implementation of the above code. Download Sample