0

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();
        }

    }
Darth Coder
  • 1,738
  • 7
  • 33
  • 56

1 Answers1

2

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

result

the best part is animation is working flawlessly

pushpraj
  • 13,458
  • 3
  • 33
  • 50
  • I can't use XAML because I have generated everything (the table and everything else on the UI) using C# code. So, the hover effects must also be done using c# code. Can you give me a solution for that? – Darth Coder Jul 15 '14 at 02:11
  • I updated the answer. just use the code and remove any timer etc. – pushpraj Jul 15 '14 at 02:17
  • I used it, the error is "The type or namespace name 'ColorAnimation' could not be found...". How do I fix this? Is it under System or something? – Darth Coder Jul 15 '14 at 02:21
  • Fixed. Used "System.Windows.Media.Animation.ColorAnimation" Thanks! – Darth Coder Jul 15 '14 at 02:22
  • While this does the animation, this holds my main UI thread for 1 sec which means that there is a visible lagg when moving to the new cell in the table, waiting for the previously hovered cell's color to return to silver and have the color of the newly hovered cell change to green. I guess I need a separate thread to manage the animation? – Darth Coder Jul 15 '14 at 02:24
  • animation itself use separate thread, however updates are performed on UI thread only. You may post a working sample of your code, lets see how we can improve the performance. – pushpraj Jul 15 '14 at 02:31
  • I did attempt a couple of ways seems like we are limited by the framework here. it is not the animation which is lagging, but the events are lagging. just wanted to check with you if the `FlowDocument` is a necessacity? – pushpraj Jul 15 '14 at 03:32
  • Actually I intended to use a Canvas instead but have not been able to add the Table I created (can't convert from Windows.Document to UI Element). Thus, I used a flow document instead. Does that affect the lagg? – Darth Coder Jul 15 '14 at 03:40
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/57298/discussion-between-pushpraj-and-darth-coder). – pushpraj Jul 15 '14 at 04:06