lordnoob
lordnoob

Reputation: 355

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?

Upvotes: 1

Views: 1189

Answers (3)

loopedcode
loopedcode

Reputation: 4893

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>

Upvotes: 4

H_Dev
H_Dev

Reputation: 31

    private BackgroundWorker bw = new BackgroundWorker();

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        //Background Worker code///
        bw.WorkerReportsProgress = true;
        bw.DoWork += bw_DoWork;
        bw.ProgressChanged += bw_ProgressChanged;
        bw.RunWorkerCompleted += bw_RunWorkerCompleted;
        bw.RunWorkerAsync();

        //Progress Bar Window
        grdProgress.Visibility = Visibility.Visible;
    }
    private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        //something to do
    }

    private void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        //Progress Bar Window close
        grdProgress.Visibility = Visibility.Hidden;
    }

    private void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        prg.Value = e.ProgressPercentage;
    }


  bw.ReportProgress(value);

Upvotes: 0

Sarel Louw
Sarel Louw

Reputation: 378

If you make use off MVVm and you are binding to your viewmodel then give this a try

Bind a visibility converter to the rectangle and only show it when the value is something like true and false?

then in the background worker you set the value before and after the time

https://www.rhyous.com/2011/02/22/binding-visibility-to-a-bool-value-in-wpf/

Upvotes: 0

Related Questions