I want to make a service call only once the page is loaded , but the page constructor doesn't support the async await pattern , so I have to make the same in OnAppearing with some checks so the service call is made only once.
What is best practise for the same i.e. if I want to make a service call only once.
You can use a task to do the job.
See:
public MyClass()
{
... // Your stuff goes here
Initialize();
}
private async void Initialize()
{
Task.Run(async () =>
{
await ServerObjectReference.AsyncMethod();
});
}
Related
I've followed the following example which works well.
https://developer.xamarin.com/guides/cross-platform/application_fundamentals/web_services/walkthrough_working_with_WCF/
The only issue is, the example uses button clicks to load data. Now i have two separate calls different functions, and i need one to wait for the other, for example:
So when i call function2 for example, i want to wait for function1 first.
_client.function1Async();
_client.function2Async();
I could put the function2 call inside the function1Completed handler, but i was looking to use async wait with it. When i use async task, i get an error saying cannot await a void. But the web service async function in the example is a void
If i had 6 calls that i wanted to run, it would become very messy.
void _client_function1Completed(object sender,UpdateOrdersByWardCompletedEventArgs e
{
}
void _client_function2Completed(object sender,UpdateOrdersByWardCompletedEventArgs e
{
}
Hope this makes sense.
You could Task.ContinueWith
ContinueWith creates a continuation that executes asynchronously when task 1 completes.
var task1 = Task.Factory.StartNew( () => { func1(); } );
Task task2 = task1 .ContinueWith( (i) => { func2(); } );
Not sure if I understood well what you are trying to achieve, but I guess you can try something like this:
Given some lengthy (and blocking) methods:
public void func1()
{
Console.WriteLine("func1");
System.Threading.Thread.Sleep(5000);
}
public void func2()
{
Console.WriteLine("func2");
System.Threading.Thread.Sleep(5000);
}
You could add the ability to run the lengthy stuff asynchronously by doing this:
public async Task function1Async()
{
await Task.Run(() => {
func1();
});
}
public async Task function1Async()
{
await Task.Run(() => {
func2();
});
}
Now you can choose to run 'func1' and 'func2' either asynchronously or synchronously, for example:
function1Async().Wait(); // will block
function2Async(); // will run asynchronously
So, for your particular case, given that you already have the two async methods, I guess that all you need to do is to call them as shown above.
This question already has answers here:
The calling thread cannot access this object because a different thread owns it.WPF [duplicate]
(6 answers)
Closed 6 years ago.
Im really stuck here... I have a XAML Page UI and want to call an async function everytime the user interacts with the UI.
I use SignalR for networking:
public static class ProtocolClient
{
private static HubConnection hubConnection;
private static IHubProxy protocolHubProxy;
public static async void connect(string server)
{
hubConnection = new HubConnection(server);
protocolHubProxy = hubConnection.CreateHubProxy("ProtocolHub");
protocolHubProxy.On<Body>("BodiesChanged", body =>
//call a callback to return body
);
await hubConnection.Start(); //wait for connection
}
public static async void sendTouch(Touch touch)
{
Body body = await protocolHubProxy.Invoke<Body>("GetBodyForTouch", touch);
//call a callback to return body
}
}
UI:
public sealed partial class MainPage : Page
{
[...]
private void Canvas_PointerPressed(object sender, PointerRoutedEventArgs e)
{
[...]
switch (ptrPt.PointerDevice.PointerDeviceType)
{
case Windows.Devices.Input.PointerDeviceType.Mouse:
if (ptrPt.Properties.IsLeftButtonPressed)
{
//call sendTouch
}
break;
default:
break;
}
[...]
}
}
I need a callback which can modify the UI. How can I call connect and sendTouch out of the UI and pass them a callback?
You don't need a callback. Just add the code after the await hubConnection.Start(); statement. Your method is 'cut in multiple methods' and will 'continue' after the await comes back. The await works like a blocking statement, but will not freeze the gui.
public static async void connect(string server)
{
hubConnection = new HubConnection(server);
protocolHubProxy = hubConnection.CreateHubProxy("ProtocolHub");
protocolHubProxy.On<Body>("BodiesChanged", body =>
//call a callback to return body
);
await hubConnection.Start(); //wait for connection
// add code here.
}
When handling commands async (from gui events), don't forget to disable controls to prevent executing the command more than ones.
Don't use async void methods. If you don't need to return a value, use async Task - if you do, use async Task<SomeType>.
Then, when you need to call an async method (and by convention, these should be named like ConnectAsync and SendTouchAsync), await it:
await SendTouchAsync(...);
When the asynchronous workflow ends, your continuation will be marshalled back to the UI thread (because you awaited from within a synchronization context), and you can manipulate the UI easily.
await kind of appears to work when you use async void, but the problem is that the caller has no way of tracking the asynchronous workflow - as far as the caller is concerned, the method just ended right then and now, and the code in the caller continues as usual.
Make sure to mark Canvas_PointerPressed as async too - sadly, in this case, it must be async void. Make sure to never call the event handler directly - the UI thread can handle the callbacks correctly, your code can't. If you need the same logic from other methods, just separate it into a proper async Task method and await that from the event handler.
I am using MVVM and WPF, now I am calling async process from my viewmodel class's constructor like this:
Task.Run(() => this.MyMetho(someParam)).Wait();
The problem with this is that screen freeze it until the task ends.
Another way is to create a LoadDataMethod in the ViewModel and call it from the view in the event handler for UserControl_Loaded something like this
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
{
VMRep vm = (VMRep)this.DataContext;
await vm.LoadDataMethod();
}
that way works better, but I guess there is a better way to do the load of async data for a View.
Thanks for your comments
You can create async factory method, and make your constructor private or protected
public static async bool Create() {
var control = new UserControl();
return await LoadDataMethod();
}
I guess there is a better way to do the load of async data for a View
The key is to realize that all ViewModels must initialize immediately. If you think about it, it doesn't make sense to initialize them asynchronously, because when WPF constructs your VM, it has to show it right away. Not 10 seconds from now whenever the download completes.
So, shift your thinking a bit, and the answer will become clearer. Your VM needs to initialize immediately, but you don't have the data to display yet. So the appropriate thing to do is to immediately initialize to a kind of "loading..." state and start the download of the data. When the data arrives, then you update the VM to show the data.
You can do it the way you have it:
private async void UserControl_Loaded(object sender, RoutedEventArgs e)
{
VMRep vm = (VMRep)this.DataContext;
await vm.LoadDataMethod();
}
but this doesn't provide a clean way for your View to detect whether the data is loading or has completed loading. I wrote a data-bindable Task<T> wrapper (updated version here) that helps with this kind of situation. It can be used like this:
public MyViewModel()
{
MyData = NotifyTask.Create(LoadDataAsync());
}
public NotifyTask<TMyData> MyData { get; }
and then your View can data-bind to MyData.Result to get to the data, as well as other properties such as MyData.IsNotCompleted to show/hide "loading" indicators.
Well, since I don't know exactly what you're trying to accomplish I'm trying my best to give you a brief explanation about Lazy
private Lazy<Task<string>> getInfo;
In this case I'm holding a field with Lazy<Task<string>> in your case it would be Lazy<Task<VMRep>>. I'm using this field, so that you can call this lazy initialzier inside your class.
public Laziness()
{
this.getInfo = new Lazy<Task<string>>(async () => await this.GetInfo());
}
In the constructor I'm assigning the value to the lazy field. In this case with the method GetInfo()
public string GetLazyInfo
{
get
{
return this.getInfo.Value.Result;
}
}
Exposing the getInfo field with a public property. And returning the result from the task inside the lazy.
private async Task<string> GetInfo()
{
await Task.Run(async () => await Task.Delay(5000));
return await Task.Run(() => "test");
}
And finally the method, where your magic can happen.
I'm new to C#. I
I've a problem related to async methods and await function in C# windows phone 8.0.
I've this http request and can get response. This is working fine and There is no issue...
public async static Task<List<MyAccountData>> GetBalance()
{
HttpClient = new HttpClient();
string response = await client.GetStringAsync("http://xxxx/xxx/xxx");
List<MyAccountData> data = JsonConvert.DeserializeObject<List<MyAccountData>>(response);
return data;
}
I've another class call MainModel
public class MainModel
{
public void LoadData()
{
}
}
So My problem is, I want to call that GetBalance method with in MainModel class and parse data to LoadData method(simply want 2 access Data with in LoadData method). LoadData method can't change return type or can't use async. So how is this possible?
If you want a responsive UI - i.e., one that has a chance of being accepted in the store - then blocking on the async operation is not an option.
Instead, you have to think a bit about how you want your UI to look while the operation is in progress. And while you're thinking about that, also think about how you would want your UI to respond if the operation errors out.
Then you can code up a solution. It's possible to do this with async void, if you catch all exceptions and handle them cleanly:
public async void LoadData()
{
try
{
... // Set up "loading" UI state.
var balance = await GetBalanceAsync();
... // Set up "normal" UI state.
Balance = balance;
}
catch
{
... // Set up "error" UI state.
}
}
However, I prefer to use a type I created called NotifyTaskCompletion, which is a data-bindable wrapper for Task<T> (described in my MSDN article). Using NotifyTaskCompletion, the LoadData becomes much simpler:
public void LoadData()
{
GetBalanceOperation = new NotifyTaskCompletion<Balance>(GetBalanceAsync());
}
public NotifyTaskCompletion<Balance> GetBalanceOperation // Raises INotifyPropertyChanged when set
Then your UI can data-bind to properties on NotifyTaskCompletion<T>, such as IsNotCompleted (for the "loading" state), IsSuccessfullyCompleted and Result (for the "normal" state), and IsFaulted and ErrorMessage (for the "error" state).
There is no difference to use async await in Windows Phone 8 dev:
public class MainModel
{
public async void LoadData()
{
var data = await Foo.GetBalance();
}
}
Depends on whether you want LoadData to be synchronous (not returning until all the data has been streamed in over HTTP, and locking up the UI until then), or to begin the process and return immediately. If you can't change LoadData to async, then those are your only two options.
If you want LoadData to be synchronous:
public void LoadData() {
var task = GetBalance();
var result = task.Result; // will lock up the UI until the HTTP request returns
// now do something with result
}
If you want it to start a background process and return immediately, but for some reason don't want to mark LoadData as async:
public void LoadData() {
BeginLoadData();
}
private async void BeginLoadData() {
var result = await GetBalance();
// now do something with result
}
Though really, there's no reason not to go ahead and make LoadData async. async void does not force you to change the callers in any way (unlike Async<Task<T>>), and it's assignment-compatible with plain old non-async delegates:
public async void LoadData() {
var result = await GetBalance();
// now do something with result
}
// ...
LoadData(); // works just fine
Action myAction = LoadData; // works just fine
As you are working on asynchronus operations you need to wait until the operation is completed.The return type async/await method is always Task(TResult), to access the result of the async/await you need to use Result Property.The get accessor of Result property ensures that the asynchronous operation is complete before returning.
public void LoadData()
{
var data = GetBalance().Result;
}
I am using MvvmLight and have implemented communication between some of my ViewModels using the MessengerInstance.Send(...) method. It works great!
Recently, though, I have moved from using Synchronous methods to async methods to retrieve data and it looks like this breaks messaging (probably because it executes on a different thread). For example:
public ICommand SomeCommand { get { return new RelayCommand(DoSomething); } }
private async void DoSomething(object obj)
{
//Used to be SomeWcfService.DoSomething(); with some logic afterward
await SomeWcfService.DoSomethingAsync().ContinueWith(task => { //Some logic after method completes });
MessengerInstance.Send(SomeDataToSend, MessageIdentifer.DoSomething);
}
Instead of using a continuation, just put it after the await:
private async void DoSomething(object obj)
{
//Used to be SomeWcfService.DoSomething(); with some logic afterward
var result = await SomeWcfService.DoSomethingAsync();
// .ContinueWith(task => { //Some logic after method completes });
// use result here!
MessengerInstance.Send(SomeDataToSend, MessageIdentifer.DoSomething);
}
If there is no result returned from DoSomethingAsync, you can just leave out the result, and put your code in place.
The continuation, as you wrote it, will not run on the same synchronization context. The await keyword is actually asynchronously waiting your continuation, not the async method from WCF, as well.
If your "some logic" is asynchronous, you can use await within that code, as well.