多线程asnc应用程序中的沙漏游标

时间:2018-03-23 07:43:01

标签: c# wpf multithreading wpf-controls sta

当我的应用程序出现大问题时,我正在尝试实现游标更改。 我正在尝试这个

public class CursorWait : IDisposable
{
    public CursorWait(bool appStarting = false, bool applicationCursor = false)
    {
        // Wait
        Cursor.Current = appStarting ? Cursors.AppStarting : Cursors.WaitCursor;
        if (applicationCursor) Application.UseWaitCursor = true;
    }

    public void Dispose()
    {
        // Reset
        Cursor.Current = Cursors.Default;
        Application.UseWaitCursor = false;
    }
}

还有这个

public static class UiServices
{
private static bool IsBusy;

public static void SetBusyState()
{
    SetBusyState(true);
}
    private static void SetBusyState(bool busy)
    {
        if (busy != IsBusy)
        {
            IsBusy = busy;
            Mouse.OverrideCursor = busy ? Cursors.Wait : null;

            if (IsBusy)
            {
                new DispatcherTimer(TimeSpan.FromSeconds(0), DispatcherPriority.ApplicationIdle, dispatcherTimer_Tick, Application.Current.Dispatcher);
            }
        }
    }
    private static void dispatcherTimer_Tick(object sender, EventArgs e)
    {
            var dispatcherTimer = sender as DispatcherTimer;
            if (dispatcherTimer != null)
            {
                SetBusyState(false);
                dispatcherTimer.Stop();
            }
    }
}

但两种情况都给我错误:调用线程必须是STA,因为许多UI组件都需要这个。

在我的应用程序中,我正在使用特殊调用来创建数据库和用户权限。 此代码如下所示:

Task.Run(() => TryExecute(securedAction)).ContinueWith(taskResult =>
            {
                var application = Application.Current;
                if (DoneActionCanBeDone(doneAction, taskResult))
                {
                    if (application != null)
                    {
                        application.Dispatcher.InvokeAsync(() => doneAction(taskResult.Result));
                    }
                    else
                    {
                        doneAction(taskResult.Result);
                    }
                }
                else if (taskResult.Status != TaskStatus.RanToCompletion)
                {
                    if (application != null)
                    {
                        application.Dispatcher.InvokeAsync(
                            () => InvokeRollbackAction(rollbackAction, suppressError, taskResult));
                    }
                    else
                    {
                        InvokeRollbackAction(rollbackAction, suppressError, taskResult);
                    }
                }
            });

我的光标更改应在Task.Run之前开始,在结束之后结束。 谢谢你的建议。

3 个答案:

答案 0 :(得分:1)

我将一些代码放在winforms应用程序中并从单击事件处理程序运行它。

    private void button1_Click(object sender, EventArgs e)
    {
        var cw = new CursorWait(false, true);

这没问题。 这让我觉得如果你收到错误,你可能会从非ui线程中调用它。 将您的呼叫转移到ui线程上的某个位置。

除非您使用旧版本的.net,否则我建议您查看异步并等待任务,而不是使用所有可以继续使用的内容。

答案 1 :(得分:1)

这里有一个类似MVVM的方法,利用异步等待:

观点:

class MainWindowViewModel : ViewModelBase
{
    public MainWindowViewModel ( )
    {
        DoMethod = new DelegateCommand ( Method );
    }

    public async void Method ( )
    {
        // Lets define our time consuming worker
        string Worker ( )
        {
            Thread.Sleep ( 5000 );

            return "result";
        };

        // This part executes in the main thread
        IsBusy = true;

        // The Scheduler will direct the main thread to execute something else while the task is not done
        var result = await Task.Factory.StartNew ( Worker );

        // Task is done, the rest will execute back in the main thread
        IsBusy = false;
    }

    public ICommand DoMethod { get; private set; }

    public  bool  IsBusy { get { return _isBusy; }
                           set { _isBusy = value; OnPropertyChanged ( ); } }
    private bool _isBusy;
}

viewmodel:

Locale.current.localizedString(forRegionCode:)
// "NZ" -> "New Zealand"

即使你没有使用MVVM模式,async await结构在你的情况下应该仍然有效。

答案 2 :(得分:-1)

如果你的目标是在开始任务/漫长过程之前更改光标,然后完成任务/漫长过程更改光标恢复正常那么下面的代码可能会有所帮助。

如果以下代码符合您的情况,请告诉我。

    private void LongProcess()
    {
        // Write your code/call method to change cursor
        Cursor = Cursors.Wait;

        Task.Factory.StartNew(() =>
        {
            // Write your code which do long process or
            // call method which do the same
            System.Threading.Thread.Sleep(10000);

        }).ContinueWith(t =>
        {
            Dispatcher.Invoke(() =>
            {
                // Write your code/call method to change cursor back to normal
                Cursor = Cursors.Arrow;
            });
        });
    }