views:

237

answers:

3

When a user clicks in certain places in my control, I want to change the color of some rows and columns in my grid, then fade it back to the normal color, within say 500ms or so. I haven't decided whether to use Winforms or WPF yet, so advice in either of those technologies would work. Thank you.

Edit: I understand I could do this by just calling Paint in a loop within the click event, properly setting the drawing parameters. However I believe that would block the UI, and I would like to be more responsive than that.

A: 

At its simplest, a fade effect like this just requires a timer of some sort that gradates the color back towards normal with each tick. The faster the time, the more discrete colors you will display from start to finish, and the smoother the overall effect will be (WPF may have something built-in to do this).

You definitely do not want to repaint in a loop. As you pointed out this will block the UI, and also you would not be able to control how long the loop takes (different machines will render the same number of steps from highlight color to normal in different lengths of time).

MusiGenesis
+2  A: 

WPF has very good support for animations. Animations are supported from both xaml and code behind, so you should be able to achieve any look that you are going for.

The MSDN Animation Overview for WPF looks to have a lot of good information for getting you started.

Todd White
+1 to WPF support for animations. Wayyy simpler than multi-threading in Winforms
chakrit
Animations are very good indeed. Although because they get wordy really fast, without Blend Im lost.
Artur Carvalho
+1  A: 

Here is one way you could handle the fade:

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace WindowsApplication1
{
    public class FadeForm : Form
    {
        private Timer fadeTimer;
        private Panel fadePanel;
        private Button fadeButton;
        /// <summary>
        /// Required designer variable.
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// Clean up any resources being used.
        /// </summary>
        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
        protected override void Dispose( bool disposing )
        {
            if ( disposing && ( components != null ) )
            {
                components.Dispose();
            }
            base.Dispose( disposing );
        }

        #region Windows Form Designer generated code

        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        private void InitializeComponent()
        {
            this.fadePanel = new System.Windows.Forms.Panel();
            this.fadeButton = new System.Windows.Forms.Button();
            this.SuspendLayout();
            // 
            // fadePanel
            // 
            this.fadePanel.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.fadePanel.Location = new System.Drawing.Point( 4, 8 );
            this.fadePanel.Name = "fadePanel";
            this.fadePanel.Size = new System.Drawing.Size( 276, 104 );
            this.fadePanel.TabIndex = 0;
            // 
            // fadeButton
            // 
            this.fadeButton.Location = new System.Drawing.Point( 104, 116 );
            this.fadeButton.Name = "fadeButton";
            this.fadeButton.Size = new System.Drawing.Size( 75, 23 );
            this.fadeButton.TabIndex = 1;
            this.fadeButton.Text = "Fade";
            this.fadeButton.UseVisualStyleBackColor = true;
            this.fadeButton.Click += new System.EventHandler( this.HandleFadeButtonClick );
            // 
            // FadeForm
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF( 6F, 13F );
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size( 284, 142 );
            this.Controls.Add( this.fadeButton );
            this.Controls.Add( this.fadePanel );
            this.Name = "FadeForm";
            this.Text = "Fade Form";
            this.ResumeLayout( false );

        }

        #endregion

        public FadeForm()
        {
            InitializeComponent();

            this.fadeTimer = new Timer();
        }

        private void HandleFadeButtonClick( object sender, EventArgs e )
        {
            this.fadeTimer.Tick += new EventHandler( HandleFadeTimerTick );
            this.fadePanel.BackColor = Color.Red;
            this.fadeTimer.Interval = 100;
            this.fadeTimer.Start();
        }

        void HandleFadeTimerTick( object sender, EventArgs e )
        {
            Color panelColor = this.fadePanel.BackColor;

            if ( panelColor.A > 0 )
            {
                this.fadePanel.BackColor = 
                    Color.FromArgb( 
                        Math.Max( panelColor.A - 20, 0 ), 
                        panelColor.R, panelColor.G, panelColor.B );
            }
            else
            {
                this.fadeTimer.Stop();
            }
        }
    }
}

Unfortunately, this approach doesn't seem to work with rows in a DataGridView. I don't know the reason, but the color doesn't show at all if the alpha component of the color isn't 255. If you can find a way around that, this code might help.

Jeff Hillman