0

I am trying to implement cursor changing when my application making big issue. I was trying this

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

and also this

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

But both cases giving me error: The calling thread must be STA, because many UI components require this.

In my app, I am using special call to make some stuff on DB and user privileges. This code looks like this:

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

My cursor changing should start before Task.Run and end after its ending. Thanks for advices.

mikroice90
  • 137
  • 1
  • 9
  • 1
    Its hard to know what you are actually doing here, at best this seems very convoluted, and just for reference `DoneActionCanBeDone` is a terrible name. However all that aside, whats the current problem? is the cursor not changing at the right time? (not that i can see you actually change it) – TheGeneral Mar 23 '18 at 08:30
  • 2
    You didn't show how you actually use your `CursorWait ` class – Evk Mar 23 '18 at 08:31
  • When im using SetBusyState(); or using(WaitCursor _waitCursor = new WaitCursor()){ //my method Tusk.Run etc. } I always have STA error as i describe earlier – mikroice90 Mar 23 '18 at 11:30

3 Answers3

1

I put some of your code in a winforms app and ran it from a click event handler.

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

That worked no problem. Which makes me think you're probably invoking that from a non ui thread if you get an error. Move your call to somewhere which is on the ui thread.

Unless you're using an old version of .net I also recommend you take a look at async and await a task rather than using all that continuewith stuff.

Andy
  • 11,864
  • 2
  • 17
  • 20
1

Here's a little MVVM like approach leveraging async await:

The view:

<Grid>
    <Grid.Style>
        <Style TargetType="{x:Type Grid}">
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsBusy}" Value="true">
                    <Setter Property="Cursor" Value="Wait" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Grid.Style>

<!-- ... --> 

    <Button Command="{Binding DoMethod}" />
</Grid>

The viewmodel:

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

Even if you're not using the MVVM pattern, the async await construct should still be valid in your case.

Seb
  • 620
  • 1
  • 5
  • 11
-1

If your goal is to change cursor of an application before starting task/long process and then on completion of task/long process change cursor back to normal then may be below code is helpful.

Let me know if below code matches your scenario.

    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;
            });
        });
    }
Advait Baxi
  • 1,530
  • 14
  • 15