如何使用 BackgroundWorker 来 show/hide WPF UI 元素?

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

我有一个矩形,我想让它可见,然后我想等待 500 毫秒,然后我想让它再次不可见。

最初我试过这个代码:

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

我尝试了那两条中间线,因为它们据说会强制 windows 更新,但这只是暂停半秒钟,没有改变任何类型的矩形。

所以我听说了 BackgroundWorkers 以及我应该如何使用它们。经过一些简短的阅读,我想出了这个。请注意,Shoot 订阅了 Canvas 上的 MouseDown 事件,该事件之前有效:

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();
    }

现在它连半秒都没有停顿,向我表明工人没有做任何事情。我该如何解决这个问题,并制作矩形 appear/disappear?

如果您使用 MVVm 并绑定到您的视图模型,请尝试一下

将可见性转换器绑定到矩形,并且仅在值类似于 true 和 false 时显示它?

然后在后台worker中设置时间前后的值

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

    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);

在 wpf 中使用后台工作者来管理动画是个坏主意。动画应该 运行 来自 Storyboard。它可以通过 xaml 或在代码中指定。

你的动画矩形问题很简单 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>

对于更复杂的动画,您可以使用 Blend 进行交互式设计。

评论后的更新回复: 如果你想显示和消失,你必须从父容器中操作它,因为一旦矩形隐藏,它就不会响应鼠标事件。

您可以将矩形放在网格中并按名称引用它以更改其在动画中的可见性。

<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>