I need help with writing a delay code to add an effect to my mouse_hover when it leaves a cell in a table. When the mouse enters the cell, it colors the border to green. When it leaves the cell, the color must slowly fade back to its original color (silver) within 1 second. During this time, the user must be able to hover across other cells, uninterrupted. Here's what I have tried so far:
//cell hover effects
System.Timers.Timer timer = new System.Timers.Timer(1);
TableCell tc;
private void cell_MouseEnter(object sender, MouseEventArgs e)
{
tc = (TableCell)sender;
tc.BorderBrush = Brushes.Green;
}
private void cell_MouseLeave(object sender, MouseEventArgs e)
{
tc = (TableCell)sender;
timer.Start();
timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
tc.BorderBrush = Brushes.Silver;
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
tc.BorderBrush = Brushes.Silver;
timer.Stop();
}
This code gives me an error when I move to another cell since another thread is working with the current cell. Can someone please help me fix this or show me a better way to achieve this?
Need C# code solution, not XAML
Full code for reference:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
InitTable();
}
private void InitTable()
{
//Canvas task1Canvas = new Canvas();
Table symptomTable = new Table();
//task1Canvas.Children.Add(symptomTable);
FlowDocument flowDoc = new FlowDocument();
flowDoc.Blocks.Add(symptomTable);
//symptomTable.CellSpacing = 128;
// Create N columns and add them to the table's Columns collection.
int numOfCols = 14;
for (int i = 0; i < numOfCols; i++)
{
symptomTable.Columns.Add(new TableColumn());
symptomTable.Columns[i].Width = new GridLength(128); //cell width
}
// Create and add an empty TableRowGroup Rows.
symptomTable.RowGroups.Add(new TableRowGroup());
//Add the first row to the table
symptomTable.RowGroups[0].Rows.Add(new TableRow());
//Configure the table head row
TableRow currentRow = symptomTable.RowGroups[0].Rows[0];
// Add the header row with content,
currentRow.Cells.Add(new TableCell(new Paragraph(new Run("August"))));
for (int n = 1; n <= 13; n++)
currentRow.Cells.Add(new TableCell(new Paragraph(new Run((10+n).ToString()))));
//Add the remaining rows
int row = 1;
string[] rowHeaders = new string[] { "river", "explosion", "flu", "airport", "chills", "morning", "tech", "truck", "cold" };
foreach (string label in rowHeaders)
{
symptomTable.RowGroups[0].Rows.Add(new TableRow());
//Configure the table head row
currentRow = symptomTable.RowGroups[0].Rows[row++];
// Add the header row with content,
currentRow.Cells.Add(new TableCell(new Paragraph(new Run(label))));
for (int n = 1; n <= 13; n++)
currentRow.Cells.Add(new TableCell(new Paragraph(new Run(""))));
for (int n = 1; n < currentRow.Cells.Count; n++)
{
currentRow.Cells[n].BorderThickness = new Thickness(3, 3, 3, 3);
currentRow.Cells[n].BorderBrush = Brushes.Silver;
currentRow.Cells[n].MouseEnter += new MouseEventHandler(cell_MouseEnter);
if(label != "chills")
currentRow.Cells[n].MouseLeave += new MouseEventHandler(cell_MouseLeave);
}
}
//Add the given flow document to the window
this.Content = flowDoc;
}
//cell hover effects
System.Timers.Timer timer = new System.Timers.Timer(1);
TableCell tc;
Thread animatationThread;
private void cell_MouseEnter(object sender, MouseEventArgs e)
{
tc = (TableCell)sender;
//Color colour = System.Drawing.ColorTranslator.FromHtml("#66CC00");
Color greenShade = (Color)ColorConverter.ConvertFromString("#FF66CC00");
BrushConverter converter = new BrushConverter();
Brush brush = converter.ConvertFromString("#FF66CC00") as Brush;
tc.BorderBrush = brush;
//System.Threading.Thread animationThread = new System.Threading.Thread();
//animatationThread = new Thread(new ThreadStart(brush.BeginAnimation(SolidColorBrush.ColorProperty, new System.Windows.Media.Animation.ColorAnimation(Colors.Silver, TimeSpan.FromSeconds(1)))));
//brush.BeginAnimation(SolidColorBrush.ColorProperty, new System.Windows.Media.Animation.ColorAnimation(Colors.Silver, TimeSpan.FromSeconds(1)));
}
private void cell_MouseLeave(object sender, MouseEventArgs e)
{
//TableCell tc;
tc = (TableCell)sender;
//timer.Start();
//timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);
tc.BorderBrush = Brushes.Silver;
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
tc.BorderBrush = Brushes.Silver;
timer.Stop();
}
}
You may not require any code behind to achieve the same, you can do it via XAML declaratively
I have used animation to achieve the desired result
example
<DataGrid xmlns:sys="clr-namespace:System;assembly=mscorlib">
<DataGrid.Resources>
<Style TargetType="DataGridCell">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="DataGridCell">
<Border x:Name="border"
BorderThickness="2"
BorderBrush="Silver">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver"
Value="True">
<Trigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="border"
Storyboard.TargetProperty="BorderBrush.Color"
Duration="0:0:0"
To="Green" />
</Storyboard>
</BeginStoryboard>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="border"
Storyboard.TargetProperty="BorderBrush.Color"
Duration="0:0:1"
To="Silver" />
</Storyboard>
</BeginStoryboard>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding}"
Header="column" />
</DataGrid.Columns>
<sys:String>item 1</sys:String>
<sys:String>item 2</sys:String>
<sys:String>item 3</sys:String>
<sys:String>item 4</sys:String>
</DataGrid>
try the example above, this will change the color to green when mouse enter and will slowly fade to silver upon leave. also possible to mouse enter to other cells or even same cell uninterruptedly
Update
this is how you can do same in c#
private void cell_MouseLeave(object sender, MouseEventArgs e)
{
TableCell tc = (TableCell)sender;
SolidColorBrush brush = new SolidColorBrush(Colors.Green);
tc.BorderBrush = brush;
brush.BeginAnimation(SolidColorBrush.ColorProperty, new ColorAnimation(Colors.Silver, TimeSpan.FromSeconds(1)));
}
you do not need any timer, animation will work for you and will slowly fade to silver
Update 2
Based on your code and assuming based on commments that FlowDocument
is not a necessity, I come up with an alternative solution
everything is code behind
private void InitTable()
{
int numOfCols = 14;
UniformGrid grid = new UniformGrid();
grid.Columns = numOfCols;
grid.Children.Add(new TextBlock() { Text = "August", FontWeight = FontWeights.Bold });
for (int n = 1; n < numOfCols; n++)
grid.Children.Add(new TextBlock() { Text = (10 + n).ToString(), FontWeight = FontWeights.Bold });
string[] rowHeaders = new string[] { "river", "explosion", "flu", "airport", "chills", "morning", "tech", "truck", "cold" };
Style cellStyle = PrepareAnimationStyle();
foreach (string label in rowHeaders)
{
grid.Children.Add(new TextBlock() { Text = label, FontWeight = FontWeights.Bold });
for (int n = 1; n < numOfCols; n++)
grid.Children.Add(new Border()
{
BorderBrush = new SolidColorBrush(Colors.Silver),
Background = Brushes.Transparent,
BorderThickness = new Thickness(3),
Style = cellStyle
});
}
this.Content = grid;
}
Style PrepareAnimationStyle()
{
Trigger animTrigger = new Trigger();
animTrigger.Property = ContentElement.IsMouseOverProperty;
animTrigger.Value = true;
ColorAnimation toGreen = new ColorAnimation((Color)ColorConverter.ConvertFromString("#FF66CC00"), TimeSpan.FromSeconds(0));
toGreen.FillBehavior = FillBehavior.HoldEnd;
ColorAnimation toSilver = new ColorAnimation(Colors.Silver, TimeSpan.FromSeconds(1));
Storyboard sbEnter = new Storyboard();
Storyboard.SetTargetProperty(toGreen, new PropertyPath("BorderBrush.Color"));
sbEnter.Children.Add(toGreen);
Storyboard sbExit = new Storyboard();
Storyboard.SetTargetProperty(toSilver, new PropertyPath("BorderBrush.Color"));
sbExit.Children.Add(toSilver);
animTrigger.EnterActions.Add(new BeginStoryboard() { Storyboard = sbEnter });
animTrigger.ExitActions.Add(new BeginStoryboard() { Storyboard = sbExit });
Style cellStyle = new Style();
cellStyle.Triggers.Add(animTrigger);
return cellStyle;
}
result
the best part is animation is working flawlessly