WPF后台工作者UI未按预期响应

时间:2018-04-05 10:04:27

标签: c# wpf multithreading

我有一个订阅了几个方法的类,然后我在后台worker中执行。 (不确定我是否应该在后台工作程序中执行)该类触发一些事件,我想在屏幕上显示有关这些事件的信息。 流程如下: 在我调用AcceptCash方法之后,它等待用户做一些事情。当操作完成并且收到所有现金并且需要分配更改时,执行StartDispense事件并且该操作有效。我忙碌的屏幕按预期出现。

如果调用IncompleteDispense事件,我想要显示“忙”屏幕,告诉用户不完全分配,并等待几秒钟。问题是在不完整的分配事件之后几乎立即触发ProcessComplete事件。 此事件应等待不完整的分配屏幕消失,然后继续。但是我的等待部分似乎锁定了不完整的分配线程,并且不会始终显示不完整的消息,仅显示为快速闪烁,或者根本不显示。

这是我的代码的简单示例

private void continuePaymentProcess()
{
    paymentController.IncompleteDispense += PaymentModule_IncompleteDispense;
    paymentController.TransactionFinalised += PaymentModule_ProcessComplete;
    paymentController.StartDispense += PaymentController_StartDispense;

//Is this necessary??
    var worker = new BackgroundWorker();
    worker.DoWork += (o, ea) =>
    {
        paymentController.AcceptCash(items.Values.Sum(x => x.ItemAmount));
    };
    worker.RunWorkerAsync();
}

private void PaymentController_StartDispense(object sender, EventArgs e)
{
        ShowBusy();
}

private void PaymentModule_IncompleteDispense(decimal amount, CashItem[] cashItems)
{
    DispenseMessage = true;

    var worker = new BackgroundWorker();
    worker.DoWork += (o, ea) =>
    {
        if (amountToDispense > 0)       //This will only happen if a cashin was cancelled
            paymentController.PrintVoucher(amountToDispense, "123123");
    };
    worker.RunWorkerCompleted += (o, ea) =>
    {
        System.Threading.Thread.Sleep(5000);   //I think this is where my problem is
        BlankPage.MainInstance.HideBusy();
        DispenseMessage = false;
    };
    ShowBusy("INCOMPLETE DISPENSE!!!", $"Only {amount:c} was dispensed. A voucher for the rest of the money will be issued", false);
    worker.RunWorkerAsync();
}

private void PaymentModule_ProcessComplete(object sender, EventArgs e)
{
    var worker = new BackgroundWorker();
    worker.DoWork += (o, ea) =>
    {
        while (DispenseMessage) 
            System.Threading.Thread.Sleep(10);
        ShowBusy();
        foreach (var item in payItems)
        {
            try
            {
                ... Process some items
            }
            catch
            {

            }
        }
    };
    worker.RunWorkerCompleted += (o, ea) =>
    {
        HideBusy();
        ShowWelcomePage();
    };
    worker.RunWorkerAsync();
}

这是ShowBusy和HideBusy方法

public void ShowBusy(string Message = "Busy processing your request", string subMessage = "Please wait...", bool showProgress = true)
{
    this.Dispatcher.InvokeIfRequired(() => 
    {
        loadingPanel.ShowProgress = showProgress;
        loadingPanel.Message = Message;
        loadingPanel.SubMessage = subMessage;
        PanelLoading = true;
        Task.Delay(1000);
    }, true, System.Windows.Threading.DispatcherPriority.Render);
}

public void HideBusy()
{
    this.Dispatcher.InvokeIfRequired(() =>
    {
        PanelLoading = false;
    }, true, System.Windows.Threading.DispatcherPriority.Render);
}

我尽可能高优先,但没有帮助。

这是InvokeIfRequired扩展

public static void InvokeIfRequired(this Dispatcher dispatcher, Action action, bool useInvoke = false, DispatcherPriority priority = DispatcherPriority.ContextIdle)
{
    if (dispatcher == null)
    {
        return;
    }
    if (!dispatcher.CheckAccess())
    {
        if (useInvoke)
            dispatcher.Invoke(action, priority);
        else
            dispatcher.BeginInvoke(action, priority);
        return;
    }
    action();
}

0 个答案:

没有答案