Reputation: 355
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
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
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
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