How do I program a "flash" effect when updating text boxes in a windows form with C#?
Asked Answered
L

7

7

What I have is a Windows form, in C#, with 7 text boxes. Each text box updates 2 or 3 others when its value is changed and accepted. What I want to do is somehow take those text boxes that need to be updated and make them "flash" with a light back color or something. The purpose is to show the user what is being updated with an added bit of flair.

I'm not sure if there is an easy way to do this and that is why I'm asking here. I can use a timer, a while loop, and a back color with a decreasing alpha channel on the text box control back color, I think, but I want to see if there is a better way.

jQuery UI has a "Highlight" effect that shows what I want to accomplish (although I want mine to be a bit slower). Just go here to the jQuery UI Effects Demo page, select "highlight" from the drop-down box in the window, and click "Run Effect".

Edit
I had to go with my own solution based on my time and resource constraints, but text boxes do not support transparent colors as mentioned by Hans Passant. So, I used a self-stopping timer that increases the R, G, and B values until the control is completely white (R=255, G=255, B=255);

Edit 2
Wound up recoding the flash event as an extension method using a variation of George Johnston's solution after we updated to .NET 4.0. This is a much cleaner solution, I feel, and the extension method makes it automatically available to anyone using it.

Lovell answered 10/11, 2010 at 17:23 Comment(3)
I think your method is the straight forward solution. The simple of JQuery is for web-page ...Cockpit
True. The purpose of the jQuery link is to give a visual example of what I want to accomplish.Lovell
Based on the constraint on time and other limitations, I guess if my idea is OK I have to go with that one. It is by far the simplest and easiest/fastest to code with my experience and available resources. All these are great answers and I appreciate the input. I updated my question with the new method I am using.Lovell
N
12

You could spin off a seperate thread per flashing textbox as to not block your form from being used during the flashing of your textbox(s). Be sure to invoke your form as spinning of the thread will require cross threading. Full solution below.

private void Form1_Load(object sender, EventArgs e)
{
    // textBox1 is the control on your form.
    // 1000 is the total interval between flashes
    // Color.LightBlue is the flash color
    // 10 is the number of flashes before the thread quits.
    Flash(textBox1, 1000,Color.LightBlue,10);
    Flash(textBox2, 1500,Color.Green,10);
    Flash(textBox3, 100,Color.Red,10);
    Flash(textBox4, 500,Color.Brown,10);
    Flash(textBox5, 200,Color.Pink,10);
}

public void Flash(TextBox textBox, int interval, Color color, int flashes)
{
    new Thread(() => FlashInternal(textBox, interval, color, flashes)).Start();
}

private delegate void UpdateTextboxDelegate(TextBox textBox, Color originalColor);
public void UpdateTextbox(TextBox textBox, Color color)
{
    if (textBox.InvokeRequired)
    {
        this.Invoke(new UpdateTextboxDelegate(UpdateTextbox), new object[] { textBox, color });
    }
    textBox.BackColor = color;
}

private void FlashInternal(TextBox textBox, int interval, Color flashColor, int flashes)
{
    Color original = textBox.BackColor;
    for (int i = 0; i < flashes; i++)
    {

        UpdateTextbox(textBox, flashColor);
        Thread.Sleep(interval/2);
        UpdateTextbox(textBox, original);
        Thread.Sleep(interval/2);
    }
}

This avoids having to put supporting timer controls on your form.

Nahshunn answered 10/11, 2010 at 17:49 Comment(2)
Wow. This is a good idea, although I need the boss's go ahead to move from .NET 2.0. As of right now that is the framework we are targeting and do not have support for Lambda expressions. I also don't think I can get this code in and working with the project in time. Your help is appreciated, though.Lovell
We updated to .NET 4 a while ago so I wound up recoding the flash event and using a variation of your solution. Used an extension method so you can just call myTextBox.Flash(...). :) Thanks for the suggestion.Lovell
K
3

The WPF would seem perfect for this. You can build it in WPF and use it in WinForms as a HostedElement. Add new project WPF User Control, and this in xaml:

<UserControl x:Class="WpfControlLibrary1.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         mc:Ignorable="d" 
         d:DesignHeight="20" d:DesignWidth="300">
<TextBox>
    <TextBox.Triggers>
        <EventTrigger RoutedEvent="TextBox.TextChanged">
            <BeginStoryboard>
                <Storyboard AutoReverse="False" BeginTime="0" >
                    <DoubleAnimation Storyboard.TargetName="Foo"
                                 Storyboard.TargetProperty="Opacity"
                                 From="0" To="1" Duration="0:0:1"/>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </TextBox.Triggers>
    <TextBox.Background>
        <SolidColorBrush Opacity="1" x:Name="Foo" Color="LightGray" />
    </TextBox.Background>
</TextBox>
</UserControl>

(it could do a little work, but it's a start). There you have it - a fancy textbox :)

Build the solution, and a new item will appear in Toolbox - just drag & drop to your Form, the WPF will be hosted inside ElementHost element. The beauty of it is that you can do much much more in visual styles in WPF, however, it's hosted WPF which adds certain weight to your solution...

Kutaisi answered 10/11, 2010 at 17:47 Comment(1)
I've never worked with WPF before. This is really cool. Though, with a lack of time to learn at this point in time and a project that is not converted to .NET 4.0 (we have to wait for the boss's approval before converting) I have to go with a different answer. I will check into WPF, though.Lovell
L
3

Derive your own class from TextBox. Give it a Flash() method that starts the flashing. Just change the BackColor to a pastel color. Don't use alpha, that doesn't work on a TextBox.

You ought to have all instances of this class share a common Timer so they will flash at the same time. Make the timer static and reference-count the number of instances you have. Add up in the constructor, down in the Dispose(bool) override.

Lesterlesya answered 10/11, 2010 at 17:50 Comment(1)
This is a great idea and I might implement this sometime later. I have been considering making my own derived text box for special formatting and validation, so this might be in scope of that project.Lovell
D
2

Pretty old question, but I thought i would update with a more modern answer, since async/await did not exist in 2010 when the last answers answered

I also updating it to uses a nicely fading single-flash rather than a seizure-inducing on-off blink, and and changed the typing so that it is not restricted to be used on Textboxes.

Since it uses async/await, it is safe to do on the main thread without needing the delegate or the InvokeRequired check. Even if you set the duration of the fade to something long, you will still be able to interact with the application while the fade loop is running.

    private bool CurrentlyFlashing = false;
    private async void FlashControl(Control control)
    {
        Color flashColor = Color.Yellow;

        float duration = 500; // milliseconds
        int steps = 10;
        float interval = duration / steps;

        if (CurrentlyFlashing) return;
        CurrentlyFlashing = true;
        Color original = control.BackColor;

        float interpolant = 0.0f;
        while (interpolant < 1.0f)
        {
            Color c = InterpolateColour(flashColor, original, interpolant);
            control.BackColor = c;
            await Task.Delay((int) interval);
            interpolant += (1.0f / steps);
        }

        control.BackColor = original;

        CurrentlyFlashing = false;
    }

    public static Color InterpolateColour(Color c1, Color c2, float alpha)
    {
        float oneMinusAlpha = 1.0f - alpha;
        float a = oneMinusAlpha * (float)c1.A + alpha * (float)c2.A;
        float r = oneMinusAlpha * (float)c1.R + alpha * (float)c2.R;
        float g = oneMinusAlpha * (float)c1.G + alpha * (float)c2.G;
        float b = oneMinusAlpha * (float)c1.B + alpha * (float)c2.B;
        return Color.FromArgb((int)a, (int)r, (int)g, (int)b);
    }

I hard-coded the colour and timing rather than exposing them as function parameters as other answerers did, since I generally want them to be the same across my application if I reuse this.

Dogmatic answered 17/9, 2019 at 17:59 Comment(0)
C
0

If you are set on your ways in using WinForms, then with my limited knowledge, I can suggest getting third party controls to help out. A few to name are Telerik and ComponentOne. If you want something WinForms like, you can probably utilize WPF, and develop custom animations in XAML (which I think are similar to Silverlight XAML in creating UI states and animations). Other than these, I'm out of experience to provide any help.

Chainplate answered 10/11, 2010 at 17:35 Comment(1)
There seems to me little compelling reason to assume the potential difficulties of a third-party control library when you can achieve the effect that is sought here very simply yourself in a derived control. It would be interesting to know if any third-party controls implement this functionality in a different way than suggested by the question.Chitarrone
I
0

Depending on your app, one flashy way of doing this is by changing the gamma of an image of your textbox. This of course depends on how much time you want to put into this, but it's certainly doable. I've seen several tutorials on how to adjust the gamma of an image and getting an image of your control is trivial.

That said, I also believe it's nontrivial to set the backcolor of the textbox to transparent. From your wording I can only guess you want to fade the color from the underlying control's backcolor to the textbox' backcolor, in which case the problem is trivial again. But if you have i.e. a background image, you should perhaps reconsider. Nonetheless, it's still possible and I can dig up a link for you on how to do this if that's what you're trying to accomplish.

The quick'n easy solution would be to animate the text color and the back color from white to your current foreground color.

Impending answered 10/11, 2010 at 17:46 Comment(0)
G
0

If you're not interested in using threading, building on George Johnston's answer here my implementation is as follows:

private bool CurrentlyFlashing = false;
private void FlashInternal(TextBox textBox, int interval, Color flashColor, int flashes)
{
    if (CurrentlyFlashing) return;

    CurrentlyFlashing = true;
    Color original = textBox.BackColor;
    for (int i = 0; i < flashes; i++)
    {
        UpdateTextbox(textBox, flashColor);
        Application.DoEvents();
        Thread.Sleep(interval / 2);
        UpdateTextbox(textBox, original);
        Application.DoEvents();
        Thread.Sleep(interval / 2);
    }
    CurrentlyFlashing = false;
}
private delegate void UpdateTextboxDelegate(TextBox textBox, Color originalColor);
public void UpdateTextbox(TextBox textBox, Color color)
{
    if (textBox.InvokeRequired)
    {
        this.Invoke(new UpdateTextboxDelegate(UpdateTextbox), new object[] { textBox, color });
    }
    textBox.BackColor = color;
}
Graecize answered 18/9, 2013 at 22:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.