How to refresh textBlock Text after updating its text? - c#

code snippet linkI am developing windows 8 application in C#. I have 2 textBlocks in my GUI.
I get text input from user and assign it to textBlock1 using textBlock1.Text = user input;.
After that I call a method that gets some data from API in JSON and part of data it populated in textBlock2 using textBlock2.Text = "specific data";
but text of both text blocks is changed at same time that I don't want. according to code sequence text of textBlock1 should be changed earlier as textblock2 text change happens after call to API that take about 10 sec.
How can I first change text of textBlock1?
help me out as i'm new to windows development.

The API call locks the UI. If you want to update textblock1 before textblock 2 you have to make the call on a different thread.
Something like this should work.
//make the method async.
private async void button_click(object sender, RoutedEventArgs e)
{
//...
//assuming userMessage is textblock2.
userMessage.Text = await MakeAPICallAsync();
//...
}
//where MakeAPICallAsync() is another function defined as
private async Task<string> MakeAPICallAsync()
{
//API call;
return result;
}

In your method, you use
HttpResponseMessage response = client.GetAsync(userInput).Result;
string result = response.Content.ReadAsStringAsync().Result;
If you call an Async method, you should use the await statement, if the code should wait for the method call, like this:
HttpResponseMessage response = await client.GetAsync(userInput).ConfigureAwait(false);
string result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
But for that, you must change your method to async:
private async void button_Click(object sender, RoutedEventArgs e)
Perhaps, it solves your problem.
Offtopic: Because you are new, I recommend visit this page and read them, to understand Stack Overflow better.
Update:
I forgot ".ConfigureAwait(false)"

Related

async Memorystream approach in c# to get data async

My dashboard needs too much time to get data from database so I have to use async approach to handle this problem here is my code :
public async Task < Stream > LoadDashboard() {
Stream s = new MemoryStream(Encoding.Default.GetBytes(Resource.Dashboard));
s.Position = 0;
return s;
}
private async void frmMaterialDashboard_Load(object sender, EventArgs e) {
Stream dashboardData = await LoadDashboard();
dashboardViewer1.LoadDashboard(dashboardData);
//show UI components for user interact
}
My code doesn't work and I have to wait for data to come from the database. Should I add anything else ?
This part of code takes long time to load data
Stream s = new MemoryStream(Encoding.Default.GetBytes(Resource.Dashboard));
s.Position = 0;
I want to execute this part async. When my form is loaded I want to call LoadDashboard as a background task to get the data from database ,and the main thread show my user interface form .
The component link that I am using :
https://documentation.devexpress.com/#Dashboard/CustomDocument113927
From what it looks like you have no actual async work you can do, you are reading a resource in to a memory stream. Putting the async keyword on somthing does nothing by itself, the function still runs just like it used to. If you want the work to happen in the background you have to tell it to work in the background by using a new thread.
//Get rid of this async stuff here.
public Stream LoadDashboard()
{
Stream s = new MemoryStream(Encoding.Default.GetBytes(Resource.Dashboard));
s.Position = 0;
return s;
}
private async void frmMaterialDashboard_Load(object sender, EventArgs e)
{
//Start LoadDashboad in a background thread and await it.
Stream dashboardData = await Task.Run(() => LoadDashboard());
dashboardViewer1.LoadDashboard(dashboardData);
//show UI components for user interact
}
Another option is to not copy the string to a memory stream and instead get the stream directly
private void frmMaterialDashboard_Load(object sender, EventArgs e)
{
using (var dashboardStream = Resources.ResourceManager.GetStream("Dashboard"))
{
dashboardViewer1.LoadDashboard(dashboardStream);
}
//show UI components for user interact
}
I got rid of the async because DashboadViewer does not provide a way to call LoadDashboard from the background to the best of my knowledge. You will have to wait till it finishes loading or figure out how to get smaller data.

update text on a WPF page with delays

I new to WPF, and have to put a basic application together
It consists of one main window with a frame, and one page
the page has a basic status text -
the requirement is that when the page loads up, the application has to do a bunch of REST call to fetch some data from remote source, and update the status text as it fetches
problem is, as I update the text, it doesn't seem to be reflected on the page, or maybe it's being blocked - even though I've used Task
so far, I have the following code for testing:
private void Page_Loaded(object sender, RoutedEventArgs e) {
var wnd = Window.GetWindow(this);
wnd.ContentRendered += Wnd_ContentRendered;
}
private void Wnd_ContentRendered(object sender, EventArgs e) {
DisplayMessages();
}
private void DisplayMessages() {
authenticationText.Text = "text one";
var t = Task.Delay(5000);
t.Wait();
authenticationText.Text = "text two";
t = Task.Delay(5000);
t.Wait();
authenticationText.Text = "text three";
t = Task.Delay(5000);
t.Wait();
}
even though I'm waiting after each task, the UI doesn't get updated - rather it just displays text three directly after method is finished - suggestions ?
P.S: there's also a WPF loader on that page, I've noticed that it doesn't get animated as well - it seems the delay is working but everything on the UI isn't updated
I would suggest for getting the data from REST implementation , you should use the background worker and on the basis of completion of thread or progress changed you need to update the UI thread accordingly.
for getting the better insights on background worker.. kindly use this link
How to use WPF Background Worker
In your case you can use progresschanged event of the backgroundworker..
Please Create some property lets say StatusText with InotifyPropertyChanged Interface implemented and bind (use TwoWay Binding) it with the Text property of the authenticationText control .... and in the progress changed event of the backgroundworker set the value of the StatusText property,., which will automatically updates the UI.
You could try to invoke these results on the UI Thread...
Run your task normally with Task.Run or whatever. Each time you are ready to set some property on UI Thread you should invoke it through the dispatcher..
Task.Run(() =>
{
var _Temp = getSomePropTask();
Thread.Sleep(1000);
App.Current.Dispatcher.Invoke(()=>{
authenticationText.Text = _Temp;
});
});
Thanks to suggestion by Ashok, I did some background reading and have come up with the following solution using Task, async and await - which is simpler to manage than background worker threads:
private void Page_Loaded(object sender, RoutedEventArgs e) {
var wnd = Window.GetWindow(this);
wnd.ContentRendered += Wnd_ContentRendered;
}
private void Wnd_ContentRendered(object sender, EventArgs e) {
GetDataAsync();
}
private async void GetDataAsync() {
authenticationText.Text = "Connecting...";
await Task.Delay(5000);
authenticationText.Text = "Getting Member Details...";
List<MemberServiceModel> memberList = await GetMembersAsync();
// more code for handling response
}
private List<MemberServiceModel> GetMembers() {
//get all members synchronous
var request = new RestRequest("Members/Admin", Method.GET);
var response = _client.Execute<List<MemberServiceModel>>(request);
if (response.ResponseStatus != ResponseStatus.Completed) {
//TODO
_restErrorStatus = response.ResponseStatus.ToString();
_restErrorMessage = response.StatusDescription;
_logger.Error("Error in GetMembers");
_logger.Error("Status:" + _restErrorStatus);
_logger.Error("Description:" + _restErrorMessage);
}
return response.Data; ;
}
private Task<List<MemberServiceModel>> GetMembersAsync() {
//get all members asynchronous
return Task.Run(new Func<List<MemberServiceModel>>(GetMembers));
}

Returning / setting a value within a thread

I'm trying to open an OpenFileDialog within C# (codebehind, on an asp.net page). Because the regular references and the system.windows.form ones have some conflicts, I'm having to use the OpenFileDialog box within a thread, as below:
protected void Button1_Click(object sender, EventArgs e)
{
Thread newThread = new Thread(new ThreadStart(BrowseForFile));
newThread.SetApartmentState(ApartmentState.STA);
newThread.Start();
}
static void BrowseForFile()
{
System.Windows.Forms.OpenFileDialog MyFile = new System.Windows.Forms.OpenFileDialog();
if (MyFile.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
}
}
The way the page works means that this has to be in C# - using asp.net's fileupload won't work.
Now, the OpenFileDialog appears fine, and I can get values from it, but I ideally need to pass values into the thread (the BrowseForFile) and have it work with other controls on the page, in order to set things up. However, I'm very new to using threads.
Can someone show me, basically, how to get an integer from the Button1_Click into the BrowseForFile, and how I would set a label on the page from BrowseForFile?
If you use a modern version of .net you could use async-await for this. This makes it much easier for you to communicate with your dialog and to pass data to the thread that performs your background work.
To be able to use async-await:
Declare your function async
Let your function return Task instead of void and Task<TResult> instead of TResult.
There is one exception: event handlers may return void
In your async function start your other threads using Task.Run
while the other thread is running you can do other things
if you need the result: call await Task.
In your case, you'll have to change your thread class into a procedure that contains the code in your thread class. This procedure may be in any class. It must be declared async and return Task instead of void:
Of course you'll have to change your thread class into an async procedure:
private async Task MyThreadProcedureAsync(string fileName)
{
// do something really slow with fileName and return void
}
protected async void Button1_Click(object sender, EventArgs e)
{
string fileName = this.BrowseForFile();
if (!String.IsNullOrEmpty(fileName))
{
var myTask = Task.Run( () => MyThreadProcedureAsync(fileName))
// if desired do other things.
// before returning make sure the task is ready:
await myTask;
// during this wait the UI keeps responsive
}
}
private string BrowseForFileName()
{
using (var dlg = new System.Windows.Forms.OpenFileDialog())
{
// if needed set some properties; show the dialog:
var dlgResult = dlg.ShowDialog(this);
if (dlgResult == System.Windows.Forms.DialogResult.OK)
{
return dlg.FileName;
}
else
{
return null;
}
}
}

How to force execution to stop till asynchronous function is fully executed?

I'm creating a silverlight application for CRM as follow:
1- A usercontrol which is a form is filled with data retrieved from the CRM using async/await
2- A Print button that creates an instance of that usercontrol and prints it
I have a problem in the sequence of execution that causes the Print button to print the usercontrol with no data, meaning, it's executed before the async method finishes.
My code is as follows:
User control:
Public partial class ManagerContact : UserControl
// constructor and functions
...
async private void getData(string contactid)
{
// get some details of the contact
QueryExpression query = new QueryExpression();
query.EntityName = "contact";
ColumnSet cset = new ColumnSet();
cset.Columns = new System.Collections.ObjectModel.ObservableCollection<string>(new String[] { "emailaddress1","fullname" });
query.ColumnSet = cset;
IOrganizationService service = SilverlightUtility.GetSoapService();
var response = await service.RetrieveMultiple(query);
/// PROBLEM HERE
List<contacts> mycontactlist= new List<contacts>();
// a function to fill the controls in the form with the retrieved data
...
}
}
My Print Button:
private void PrintOrExport(object sender, RoutedEventArgs e)
{
PrintDocument document = new PrintDocument();
ManagerContact mymanager= new Common.ManagerContact(mycontactid);
document.PrintPage += (s, args) =>
{
// code here to prepare the pagevisual
}
document.Print("title");
}
When I click Print, a new instance of ManagerContact user control is created and execution goes through all the functions in the user control till it reaches the line
var response = await service.RetrieveMultiple(query);
and then it returns back to the Print Button function and proceeds to print the page. The problem is it skips the rest of the functions where I fill the form controls with the data and so the form is printed with no data.
I need to find a way to force execution to wait for the response to be returned and only after it gets teh response execution would go back to the main page for the rest of the print button.
Your problem is due to async void. As a general guideline, avoid async void; it should only be used for event handlers. For more information, see my MSDN article on asynchronous best practices.
So, your getData method should look like this:
private async Task getDataAsync(string contactid)
And whatever calls it should await the Task it returns, which means that function also needs to be async and return Task or Task<T>, etc.
Eventually, you'll find that your constructor cannot be async, so I recommend you create an asynchronous factory method as I describe on my blog:
class ManagerContact
{
private ManagerContact(int contactId)
{
...
}
private async Task InitializeAsync()
{
await getDataAsync();
...
}
public static async Task<ManagerContact> CreateAsync(int id)
{
var result = new ManagerContact(id);
await result.InitializeAsync();
return result;
}
}
Which you can then use like this:
private async void PrintOrExport(object sender, RoutedEventArgs e)
{
ManagerContact mymanager = await Common.ManagerContact.CreateAsync(mycontactid);
...
}

How to update TextBlock when async HttpRequest is finished?

I'm working on an app and I'm restructuring my code.
On my MainPage.xaml.cs I have a TextBlock and a ListBox. I have separate file (Info.cs) that handles the HttpRequest to get the information that I need to load.
The HttpRequest in Info.cs gets information from a weather API. When it gets all the information it puts the info in a ObservableCollection.. This ObservableCollection is bind to the ListBox.
Now, I'd like to update the TextBlock when the HttpRequest is finished, to show the user that all the information has been loaded.
How can I achieve this?
MainPage.xaml.cs:
WeatherInfo weatherInfo = new WeatherInfo();
weatherInfo.getTheWeatherData();
DataContext = weatherInfo;
WeatherListBox.ItemsSource = weatherInfo.ForecastList;
StatusTextBlock.Text = "Done.";
In the Info.cs I have a Dispatcher to fill the ForecastList:
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
ForecastList.Clear();
ForecastList = outputList;
}
What happens now is that the TextBlock instantly changes to "Done!" (doh, its Async!) but how can I change this? So it 'waits' on the ListBox to be updated? Unfortunatly there is no 'ItemsSourceChanged' event in Windows Phone.
I suggest to use the new async+await power from C# 5.0, This is actually a good practice to use async programming in WP8.
assuming you have control of getTheWeatherData() method, and that you can mark it as async method that returns Task, you will be able to call it using await modifier.
await will not block the UI, and will cause the next code lines to be executed only after the task is done.
WeatherInfo weatherInfo = new WeatherInfo();
await weatherInfo.getTheWeatherData();
DataContext = weatherInfo;
WeatherListBox.ItemsSource = weatherInfo.ForecastList;
StatusTextBlock.Text = "Done.";
Edit:
It is supported on WP 8, and on WP 7.5 through Microsoft.Bcl.Async Nuget Package
If async programming is not an option,
you can always create a callback event in WeatherInfo class that will be signaled inside getTheWeatherData(), and register to it on the UI.
One option looks as follows:
public static void DoWork(Action processAction)
{
// do work
if (processAction != null)
processAction();
}
public static void Main()
{
// using anonymous delegate
DoWork(delegate() { Console.WriteLine("Completed"); });
// using Lambda
DoWork(() => Console.WriteLine("Completed"));
}
Both DoWork() calls will end with calling the callback that is passed as a parameter.

Categories