lordnoob lordnoob - 2 months ago 13
C# Question

How to use BackgroundWorker to show/hide WPF UI element?

I have a rectangle which I want to make visible, then I want to wait for 500 milliseconds, then I want to make it invisible again.

Initially I tried this code:

MuzzleFlash.Visibility = Visibility.Visible;
Thread.Sleep(500);
this.UpdateLayout();
this.InvalidateVisual();
MuzzleFlash.Visibility = Visibility.Collapsed;


I tried those two intermediate lines as they supposedly forced windows to update, but all this did was pause for half a second without changing any sort of rectangles.

So I heard about BackgroundWorkers and how they're what I should use. After some brief reading, I came up with this. Note that Shoot is subscribed to a MouseDown event on a Canvas, which worked previously:

private void Shoot(object sender, System.Windows.Input.MouseButtonEventArgs e)
{

BackgroundWorker UIUpdater = new BackgroundWorker();
UIUpdater.WorkerSupportsCancellation = true;
UIUpdater.WorkerReportsProgress = false;

UIUpdater.DoWork += new DoWorkEventHandler(UI_DoWork);
UIUpdater.RunWorkerCompleted += new RunWorkerCompletedEventHandler(cancelUIUpdate);

}

private void UI_DoWork(object sender, DoWorkEventArgs e)
{
MuzzleFlash.Visibility = Visibility.Visible;
Thread.Sleep(500);
this.UpdateLayout();
this.InvalidateVisual();
MuzzleFlash.Visibility = Visibility.Collapsed;
}

private void cancelUIUpdate(object sender, RunWorkerCompletedEventArgs e)
{
BackgroundWorker bw = sender as BackgroundWorker;
bw.CancelAsync();
}


Now it doesn't even pause for half a second, indicating to me that the worker isn't doing anything. How can I fix this, and make the rectangle appear/disappear?

Answer

It is bad idea to use background worker to manage animation in wpf. Animation should run from Storyboard. It can be specified through xaml or in code.

Your question of animating a rectangle is very simple with xaml:

<Rectangle x:Name="MuzzleFlash" Height="100" Width="100" Fill="Red">
    <Rectangle.Triggers>
        <EventTrigger RoutedEvent="Loaded">
            <BeginStoryboard>
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames BeginTime="0:0:0.5"  Storyboard.TargetProperty="Visibility">
                        <DiscreteObjectKeyFrame Value="{x:Static Visibility.Collapsed}" />
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Rectangle.Triggers>
</Rectangle>

For more complex animations, you can use Blend to design them interactively.

Updated response after comments: If you want to make appear and disappear, you have to manipulate it from a parent container, as once rectangle hidden, it won't respond to mouse events.

You can put the rectangle in a grid and reference it by name to change its visibility in animation.

<Grid Background="Gray">
    <Grid.Triggers>
        <EventTrigger RoutedEvent="MouseDown">
            <BeginStoryboard>
                <Storyboard>
                    <ObjectAnimationUsingKeyFrames BeginTime="0:0:0.0"  Storyboard.TargetProperty="Visibility" Storyboard.TargetName="MuzzleFlash">
                        <DiscreteObjectKeyFrame Value="{x:Static Visibility.Visible}" />
                        <DiscreteObjectKeyFrame KeyTime="0:0:0.5" Value="{x:Static Visibility.Hidden}" />
                    </ObjectAnimationUsingKeyFrames>
                </Storyboard>
            </BeginStoryboard>
        </EventTrigger>
    </Grid.Triggers>
    <Rectangle x:Name="MuzzleFlash" Height="100" Width="100" Fill="Red">

    </Rectangle>
</Grid>
Comments