1

My function has three parts.

Part one Parameter Popup

Part two Executes the code in a new thread with ApartmentState.STA turned on.

Part three - Show ReportViewer

I am currently receiving this error the calling thread cannot access this object because a different thread owns it.

public async void AnticipatedEntriesReport(bool fund)
{
    var anticipatedReport = new AnticipatedReport(fund);
    ReportPreviewForm report = new ReportPreviewForm();
    anticipatedReport.InitializeParameters();
    if (anticipatedReport.GetParameters() != null)
    {
        await RunAsyncTask(
            () =>
            {
                report = anticipatedReport.GenerateReport(SelectedLoans);
            });

        report.Show();
    }
}

My code breaks at report.Show().

anticipatedReport.GenerateReport returns a ReportPreviewForm.

I'm wondering what am I doing wrong? I think it's based on where I created the object.

public async Task RunAsyncTask(System.Action action)
{       
    try
    {
        await ThreadManager.StartSTATask(action);
    }
    catch (Exception ex)
    {           

    }        
}

public static Task StartSTATask(System.Action func)
{
    var tcs = new TaskCompletionSource<object>();
    var thread = new Thread(() =>
    {
        try
        {
            func();
            tcs.SetResult(null);
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return tcs.Task;
}
Master
  • 2,038
  • 2
  • 27
  • 77

1 Answers1

0

Just create the report inside the task and return it to task's parent:

public async Task AnticipatedEntriesReport(bool fund)
{
    var anticipatedReport = new AnticipatedReport(fund);
    ReportPreviewForm report = null;
    anticipatedReport.InitializeParameters();
    if (anticipatedReport.GetParameters() != null)
    {
        // Generate the report inside the task and return it.
        report = await RunAsyncTask(
            () =>
            {
                var result = anticipatedReport.GenerateReport(SelectedLoans);
                return result;
            });
    }
}

and in RunAsyncTask:

public async Task<TResult> RunAsyncTask<TResult>(Func<TResult> function) 
{ 
    TResult result = default(TResult);
    UpdateBusyUi(true); 
    try 
    { 
        result = await ThreadManager.StartSTATask(function); 
    } 
    catch (Exception ex) 
    { 
        SendException(ex); 
        LoadSucceed = false; 
        Events.PublishOnUIThread(new BackgroundCompletedEvent { Header = BackgroundCompletedEvent.EntityActions.Error, Error = true }); 
    } 
    UpdateBusyUi(false); 
    return result;
}

The StartSTATask:

Task<TResult> StartSTATask<TResult>(Func<TResult> function)
{
    TaskCompletionSource<TResult> source = new TaskCompletionSource<TResult>();
    Thread thread = new Thread(() =>
        {
            try
            {
                source.SetResult(function());
            }
            catch (Exception ex)
            {
                source.SetException(ex);
            }
        });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return source.Task;
}
shlatchz
  • 1,612
  • 1
  • 18
  • 40
  • Same error here "The calling thread must be STA, because many UI components require this." and this time it doens't hit report.show() – Master Apr 27 '16 at 19:47
  • Why are you running the method with `ApartmentState.STA`? – shlatchz Apr 27 '16 at 20:19
  • Because it's a reusable method and if I want to update certain items in the UI, ApartmentState.STA will allow me..... – Master Apr 27 '16 at 20:35
  • How about this? http://stackoverflow.com/questions/5971686/how-to-create-a-task-tpl-running-a-sta-thread I fixed the answer – shlatchz Apr 27 '16 at 20:39
  • I've added `ConfigureAwait(false)`. How about now? – shlatchz Apr 27 '16 at 20:54
  • Error with ConfigureAwait, same one as earlier. – Master Apr 27 '16 at 20:57
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/110435/discussion-between-shlatchz-and-master). – shlatchz Apr 27 '16 at 21:03
  • I just tried this, RunAsyncTask - TResult could not be found, also cannot convert source type `TResult` to the target type 'object' – Master Apr 28 '16 at 13:47
  • What do you mean by "TResult could not be found"? Are you missing a reference? It should be in `using System.Threading.Tasks;` if I'm not wrong. – shlatchz Apr 28 '16 at 14:28
  • errm, yeah. Try switching `object result = null;` to `TResult result = null;`. – shlatchz Apr 29 '16 at 12:23
  • I made changes and checked them on my computer. Should work now. – shlatchz Apr 29 '16 at 15:46
  • @Master Could you please mark this answer as the correct one, if it helped you solve your problem? Thanks. – shlatchz Jun 18 '16 at 10:32