C
C#•3mo ago
Bubba

Async issue

Hi! I'm trying to perform an http get request in a graphical element of the Eto library. Thing is, my whole program freezes until the response is received and I'm unsure why.
...REST OF THE CODE...
public class Body : StackLayout
{
public Body()
{
Orientation = Orientation.Vertical;
Padding = 10;
Spacing = 10;

var label = new Label
{
Text = "Home page loading...",
Font = new Font(FontFamilies.Sans, 16),
VerticalAlignment = VerticalAlignment.Center
};

Task.Run(async () => await LoadHomePageAsync(label)));
}

private async Task LoadHomePageAsync(Label label)
{
var content = await RetrieveHomePageContentAsync();
label.Text = content;
}
...REST OF THE CODE...
public class Body : StackLayout
{
public Body()
{
Orientation = Orientation.Vertical;
Padding = 10;
Spacing = 10;

var label = new Label
{
Text = "Home page loading...",
Font = new Font(FontFamilies.Sans, 16),
VerticalAlignment = VerticalAlignment.Center
};

Task.Run(async () => await LoadHomePageAsync(label)));
}

private async Task LoadHomePageAsync(Label label)
{
var content = await RetrieveHomePageContentAsync();
label.Text = content;
}
The call is performed inside the Task.Run, did I do something wrong?
42 Replies
nathanAjacobs
nathanAjacobs•3mo ago
You don't need to use Task.Run also you are swallowing exceptions by not awaiting the Task.Run call
Angius
Angius•3mo ago
Use an async factory method Constructors cannot be async
canton7
canton7•3mo ago
You're setting label.Text from a background thread, for one
Angius
Angius•3mo ago
You should be doing the async stuff on button click, or triggered by some other event, not in the constructor
Bubba
BubbaOP•3mo ago
It's not really an event, there's a home page that is loaded when the program starts. Just calling the function outside of the constructor should fix the issue you think? Imma try
nathanAjacobs
nathanAjacobs•3mo ago
There has to be an event or override for when the page loads
Angius
Angius•3mo ago
Granted, I'm unfamiliar with Eto, but I do believe so Yep
nathanAjacobs
nathanAjacobs•3mo ago
I've also never heard of Eto
canton7
canton7•3mo ago
I'm not sure why it would be freezing though. Break the debugger when it's frozen and see what the UI thread is doing?
Bubba
BubbaOP•3mo ago
Hmm unsure what it means to "see what the UI thread is doing" But I tried to call the function outside of the constructor after creating a new instance of the class, but same issue
canton7
canton7•3mo ago
Make it freeze. Break the debugger. Use the Threads window to double-click the Main thread. See what line of code it's stuck on, and use the Call Stack window to see how it got there
Bubba
BubbaOP•3mo ago
I need to set a breakpoint right? Not sure if I made myself clear but it is only stuck visually. I have a textBox in my program and if I type some text on my keyboard while the window is stuck it gets updated after the response is received from the get request
canton7
canton7•3mo ago
No, no need to set a breakpoint
nathanAjacobs
nathanAjacobs•3mo ago
So you can click on the text box and type while it's "stuck"?
canton7
canton7•3mo ago
As I said, hit the "break" button while the UI is frozen
Bubba
BubbaOP•3mo ago
There's no need to select it, it's selected by default when the app starts Oh okay, it's called pause on my ide Found the issue 🫠 When I modify the label text, the size of the text is too big which causes the UI to freeze until it can modify it. I'll need implement lazy loading ig @canton7 @nathanAjacobs @ZZZZZZZZZZZZZZZZZZZZZZZZZ
public async Task LoadHomePageAsync()
{
var user = Program.ServiceProvider.GetRequiredService<User>();
var webClient = Program.ServiceProvider.GetRequiredService<IWebClient>();

var res = await webClient.GetAsync(user.HomePageUrl);
// CAUSES THE UI TO FREEZE
// _label.Text = res.Content;

for (var i = 0; i < res.Content.Length; i++)
{
_label.Text += res.Content[i];
await Task.Delay(10);
}
}
public async Task LoadHomePageAsync()
{
var user = Program.ServiceProvider.GetRequiredService<User>();
var webClient = Program.ServiceProvider.GetRequiredService<IWebClient>();

var res = await webClient.GetAsync(user.HomePageUrl);
// CAUSES THE UI TO FREEZE
// _label.Text = res.Content;

for (var i = 0; i < res.Content.Length; i++)
{
_label.Text += res.Content[i];
await Task.Delay(10);
}
}
Angius
Angius•3mo ago
webClient 💀
Bubba
BubbaOP•3mo ago
what about it?
Angius
Angius•3mo ago
Unless it's HttpClient just named like that WebClient is deprecated HttpClient is what you use
Bubba
BubbaOP•3mo ago
no no it's an abstraction layer for the HttpClient
Angius
Angius•3mo ago
Ah, it's fine then
nathanAjacobs
nathanAjacobs•3mo ago
Are you still using Task.Run() to call this method?
Bubba
BubbaOP•3mo ago
Not anymore
nathanAjacobs
nathanAjacobs•3mo ago
Okay I'm unsure then why it would freeze. What do you mean by freeze until it can modify
Bubba
BubbaOP•3mo ago
By freezing I mean that the UI is not responsive anymore (visually only) until the text is being modified I can still click on buttons or modify text but it will appear only after the _label.Text = … Btw the content is an entire html page, so it’s a huge text
nathanAjacobs
nathanAjacobs•3mo ago
What will only appear, what you typed? I don't see the problem. What are you trying to solve? Are you trying to prevent the user from clicking buttons while it's loading?
Bubba
BubbaOP•3mo ago
By « will only appear » I mean the result of clicking on a button for example, which should open a new page The new page will only appear after the content is loaded As mentioned, implementing lazy loading (loading the Text into the label progressively fixes this issue) I’m guessing it’s a problem that is linked to the UI library (or maybe it’s not made to load that amount of text)
nathanAjacobs
nathanAjacobs•3mo ago
To me this would mean that your UI is responsive while it's loading not frozen, since you can still click and type things
Bubba
BubbaOP•3mo ago
Yes it is still responsive, but not visually. Sorry if it was not clear
nathanAjacobs
nathanAjacobs•3mo ago
Can you show the code of the button click. I don't see how that for loop will solve it either. On the last iteration of the for loop it is literally the same as what you had before It is setting the entire text on the last iteration of the for loop
Bubba
BubbaOP•3mo ago
^ Hmm maybe the sleep allows the UI thread to perform other operations?
nathanAjacobs
nathanAjacobs•3mo ago
I thought that is the code when the page loads. I thought you said there was a button on the page that you can click while the text is loading
Bubba
BubbaOP•3mo ago
I meant a button as example, it can be anything. A text box or button
nathanAjacobs
nathanAjacobs•3mo ago
So you're saying if you add button to the page and click it, the button handler code doesn't get executed until after the text loads?
Bubba
BubbaOP•3mo ago
Yes Just tried, it gets executed after the text is loaded
nathanAjacobs
nathanAjacobs•3mo ago
That's very strange, can you show the code
Bubba
BubbaOP•3mo ago
But it means that the event of a button click is still catched Hmmm which part? 😅
nathanAjacobs
nathanAjacobs•3mo ago
The code for when that button is clicked
Bubba
BubbaOP•3mo ago
private Button CreateSearchButton()
{
var searchButton = new Button
{
Text = "Search",
Width = 30,
Height = 30,
ToolTip = "Search",
};

searchButton.Size = new Size(40, 40);
searchButton.BackgroundColor = Colors.LightGrey;
searchButton.Shown += (sender, e) =>
{
searchButton.Style = "button { border-radius: 20px; }";
};

searchButton.Click += (sender, e) =>
{
throw new Exception("ex");
};

return searchButton;
}
private Button CreateSearchButton()
{
var searchButton = new Button
{
Text = "Search",
Width = 30,
Height = 30,
ToolTip = "Search",
};

searchButton.Size = new Size(40, 40);
searchButton.BackgroundColor = Colors.LightGrey;
searchButton.Shown += (sender, e) =>
{
searchButton.Style = "button { border-radius: 20px; }";
};

searchButton.Click += (sender, e) =>
{
throw new Exception("ex");
};

return searchButton;
}
nathanAjacobs
nathanAjacobs•3mo ago
Yeah you might be right in that the UI framework is doing something behind the scenes to get the text ready for the screen without blocking the UI thread. It's strange that they would hold off other button clicks though while that's happening And again I have no idea why that for loop fixes it, I would think if anything it would make it worse
Bubba
BubbaOP•3mo ago
This library seems a bit strange, I'm used to libraries where you have a "game" loop and you handle events yourself, but Eto doesn't work this way. Not sure what's the name of this but you handle events with the var.Operation += ... There's a form which is basically a window and you just call a Display function and add the shapes and buttons, etc using the Content variable
Want results from more Discord servers?
Add your server