Title: Make a blinking label in WPF and C#
In Windows Forms, it's trivial to make a blinking label. As for most other tasks, WPF makes this much harder but gives you some extra flexibility.
In Windows Forms, you could add a Timer to a form and make it's Tick event switch the label's Foreground and Background colors. WPF doesn't have a Timer component and a label's Foreground and Background properties aren't simple colors, but you can still do something sort of similar. The following code shows this approach.
// Create a timer.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
DispatcherTimer timer = new DispatcherTimer();
timer.Tick += timer_Tick;
timer.Interval = new TimeSpan(0, 0, 0, 0, 500);
timer.Start();
}
// The timer's Tick event.
private bool BlinkOn = false;
private void timer_Tick(object sender, EventArgs e)
{
if (BlinkOn)
{
lblTimer.Foreground = Brushes.Black;
lblTimer.Background = Brushes.White;
}
else
{
lblTimer.Foreground = Brushes.White;
lblTimer.Background = Brushes.Black;
}
BlinkOn = !BlinkOn;
}
When the program starts, the window's Loaded event handler creates a System.Windows.Threading.DispatchTimer and gives it the timer_Tick event handler. When that event handler fires, it checks the BlinkOn variable to see which colors the label should display. It then sets the label's Foreground and Background properties appropriately and switches the value of BlinkOn.
This is a lot more complicated than the five lines of code you would need to do the same thing in Windows Forms, but it's a whole lot easier than doing this in a truly WPFish way. A truly WPFish approach can do this in XAML code only with no C# code, but it requires a Storyboard and an EventTrigger.
The following code shows how the program defines its Storyboard.
<Window.Resources>
<Storyboard x:Key="blinkLabel" Duration="0:0:1"
RepeatBehavior="Forever">
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="lblStoryboard"
Storyboard.TargetProperty="Background.(SolidColorBrush.Color)">
<DiscreteColorKeyFrame KeyTime="0:0:0" Value="Black" />
<DiscreteColorKeyFrame KeyTime="0:0:0.5" Value="White" />
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="lblStoryboard"
Storyboard.TargetProperty="Foreground.(SolidColorBrush.Color)">
<DiscreteColorKeyFrame KeyTime="0:0:0" Value="White" />
<DiscreteColorKeyFrame KeyTime="0:0:0.5" Value="Black" />
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
This code places the Storyboard inside the window's Resources dictionary. It defines a Storyboard named blinkLabel with a total duration of 1 second. Its RepeatBehavior is set to Forever so the Storyboard repeats itself when it finishes.
the Storyboard contains two ColorAnimationUsingKeyFrames objects. The first targets the lblStoryboard control's Background.(SolidColorBrush.Color) property. This value means the object looks at the Background property. That property isn't a simple value like a color, so it must look more closely at its value. The syntax (SolidColorBrush.Color) tells the program to look at a SolidColorBrush object's Color property.
The parentheses indicate a partially qualified property name. In this case, it's basically saying the Background property needs to be set to a SolidColorBrush object. The rest of the value indicates that we're setting that object's Color property.
Next the code gives the ColorAnimationUsingKeyFrames object two color frames. The first sets the target's color to black when the Storyboard starts. The second sets the target's color to white 0.5 seconds into the Storyboard. The result is that the label's text turns black when the animation starts, turns white 0.5 seconds later, and then the Storyboard repeats after 1 second.
The second ColorAnimationUsingKeyFrames object is similar to the first except it sets the label's Foreground color to white and then black.
That code defines the Storyboard that will animate the label's colors. Now the program needs a way to start the Storyboard running. To do that, the example uses the following trigger.
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource blinkStory}"/>
</EventTrigger>
</Window.Triggers>
This trigger, which is defined in the window's triggers, executes when the window raises its FrameworkElement.Loaded routed event. When that event occurs, the trigger creates a BeginStoryboard object for the Storyboard that is a static resource (in the window's Resources dictionary) named blinkStory. That starts the Storyboard.
If this whole thing seems absurdly arcane and cryptic, I agree. The problem is that the code is trying to do something that is naturally dynamic by using static XAML statements. That's why you get weirdnesses like creating a BeginStoryboard object to start the Storyboard when in code you would simply call a Storyboard method.
Once you have all of this working, however, you do get some extra flexibility. For example, instead of making the label's colors jump between black and white, you could make them fade gradually from one color to another. You probably wouldn't want to do that in this example, but you could.
Download the example to experiment with it and to see additional details.
|