Reputation: 51
My code looks pretty much like the following:
namespace CloudKey
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
}
private async void button_Click(object sender, RoutedEventArgs e)
{
//Begin Loading animation
Loading.Visibility = Visibility.Visible;
//Run Task
await Task.Run(() => LoginCheck());
}
async void LoginCheck()
{
await Dispatcher.InvokeAsync(
() =>
{
InitialSessionState iss = InitialSessionState.CreateDefault();
StringBuilder ss = new StringBuilder();
ss.AppendLine("some code here")
using (Runspace runspace = RunspaceFactory.CreateRunspace(iss))
{
Collection<PSObject> results = null;
try
{
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(ss.ToString());
results = pipeline.Invoke();
}
catch (Exception ex)
{
results.Add(new PSObject((object)ex.Message));
}
finally
{
runspace.Close();
Loading.Visibility = Visibility.Hidden;
if //some stuff
{
//do some things
}
else
{
//do some other things
}
}
}
});
}
}
}
I've also tried
Async void LoginCheck()
{
await Dispatcher.Invoke (() => {//Stuff});
}
with the same result. I'm not actually sure what the difference between the two are...
The task runs correctly either way, but the animation starts then freezes as soon as the task begins. :/ What should I do to make this work the way I intend it to with the loading animation animating throughout the functions?
EDIT:
I should add that I attempted to remove the
await Dispatcher.InvokeAsync(
() =>{});
and leave the rest of the function in tact, however, I get the following error when I do so:
The calling thread cannot access this object because a different thread owns it.
Upvotes: 0
Views: 808
Reputation: 149
I think all that's needed is to remove the
await Dispatcher.InvokeAsync(() => { };
surrounding the code. Looking at the Documentation for Dispatcher.InvokeAsync, it says "Executes the specified delegate asynchronously on the thread the Dispatcher is associated with." (source) The Dispatcher linked to a page is associated with the page's thread, so it's executing the code on the UI thread, still. Removing that surrounding function call should make the code simply run on a different thread because you already called Task.Run() to run it on a different thread.
EDIT: Missed the part where Loading got changed, which is owned by the UI thread. Here's an actual code sample that illustrates the issue better:
async void LoginCheck()
{
InitialSessionState iss = InitialSessionState.CreateDefault();
StringBuilder ss = new StringBuilder();
ss.AppendLine("some code here")
using (Runspace runspace = RunspaceFactory.CreateRunspace(iss))
{
Collection<PSObject> results = null;
try
{
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
pipeline.Commands.AddScript(ss.ToString());
results = pipeline.Invoke();
}
catch (Exception ex)
{
results.Add(new PSObject((object)ex.Message));
}
finally
{
runspace.Close();
Dispatcher.InvokeAsync(() => {
Loading.Visibility = Visibility.Hidden;
});
if //some stuff
{
//do some things
}
else
{
//do some other things
}
}
}
}
Because Loading.Visibility is a UI Element, it's owned by the UI thread. So surrounding just that call with Dispatcher.Invoke() will change that value from the UI Thread, while still executing the db calls on the other thread as explained above.
Upvotes: 1