proper way to return monotouch asynchronous calls - c#

Lets say i have an asynchoronous call in my monotouch project like this
context.getNameCompleted += HandleContextgetNameCompleted;
context.getNameAsync();
void HandleContextgetNameCompleted(object sender, getNameCompletedEventArgs args)
{
string name = args.Result;
}
Now how do I get another asynchronous method running that relies on the completion of the first without getting the program to crash. So for instance my second call might be
context.getAgeCompleted += HandleContextgetAgeCompleted;
context.getAgeAsync();
void HandlegetAgeCompleted(object sender, getAgeCompletedEventArgs args)
{
string age = args.Result;
}
the second method can only return a value once we return the "name" from the first person. Please provide in reasons and/or examples of how to properly use this method or any alternate solution.As usual your help is much appreciated

Fire the 2nd request when you handle the completion of the first one.
void HandleContextgetNameCompleted(object sender, getNameCompletedEventArgs args)
{
string name = args.Result;
context.getAgeCompleted += HandleContextgetAgeCompleted;
context.getAgeAsync();
}

Related

Statement performed only when method ends

I'm C# with Compact Framework and I realized something weird today. I'm calling a method by an event that applies a set to an object and when I debug, it passes by this, but just performs after the last close bracket of the method. My example:
public string Loading
{
set { lblLoading.Text = value; }
}
private void btnAuth_Click(object sender, EventArgs e)
{
Loading = "Loading...";
_presenter.PerformAuth();
}
When I debug, it passes by my first statement, applies it, but doesn't change anything on the screen... Oh, until it do PerformAuth(). After it, so, then the label value is changed. Oh, the problem isn't just by it be synchronous. The same occurs when I try to do an asynchronous task:
private void btnAuth_Click(object sender, EventArgs e)
{
ASyncResult res = BeginInvoke(new Action(() =>Loading = "Loading..."));
EndInvoke(res);
_presenter.PerformAuth();
}
I think it might be a bug in thread and in C# design implementation. And also with direct set it is stubborn to me. As you can see in the image below:
I just want to set a text in a label, call a method and unset it in an event. Why does C# get it so complicated?

Serial IO Async Issues

I've got serial data coming in to my application and by definition, it's async, so I'm running into troubles when trying to update a label to show what the incoming data is. Every now and then, I get an error on the lblRx.AsyncUpdate line, telling me the object is in use elsewhere.
At present, I use the following code;
private void IODataReceived(object sender, IODataEventArgs e)
{
lblRx.AsyncUpdate(() => lblRx.Text = string.Format("{0}:\t{1}", e.Timestamp, e.Data));
SetBackColors(false, eIODirection.In);
}
public static void AsyncUpdate(this Control ctrl, ActionCallback action)
{
if (ctrl != null)
{
if (!ctrl.IsHandleCreated && ctrl.IsDisposed)
ctrl.CreateControl(); // MSDN says CreateControl() is preferred over CreateHandle().
if (!ctrl.IsDisposed)
AsyncInvoke(ctrl, action);
}
}
The AsyncUpdate method isn't an issue (AFAIK...works well in other situations).
I think I need to put a lock on the control before calling AsyncUpdate. Or is there a better way to handle this situation?

Removing Text with an Invoke?

So, the documentation that I've found online so far regarding the Invoke property doesn't seem to be particularly good, which is actually kind of annoying, believe it or not. I understand what Invoke does - you can't safely access the GUI directly, so an invoke does it in a safe way. That's fine, but I don't understand the variables that go into the method. If I wanted to, for instance, remove text from a listbox, how would I do that? I get about this far before I get a bit lost.
private void DoStuff(string TextIWouldBeRemoving)
{
if (listboxname.InvokeRequired)
{
listboxname.Invoke(SomeMysteriousParamaters, new object[] { TextIWouldBeRemoving )};
}
}
The first parameter is the method you want to safely invoke, the second parameter is an object array of the arguments to that method
So you would write:
private void DoStuff(string TextIWouldBeRemoving)
{
if (listboxname.InvokeRequired)
{
listboxname.Invoke(DoStuff, new object[] { TextIWouldBeRemoving )};
}
else
{
// Actually remove the text here!
}
}
Invoke is all about threading.
You need to do an invoke whenever you have created a separate thread in your code, and you need to update the User Interface elements from withing the code, that is executing in that newly create thread.
You can use a BeginInvoke, instead of a synchronous Invoke method. This article has a good example:
http://msdn.microsoft.com/en-us/library/0b1bf3y3.aspx
private void button1_Click(object sender, EventArgs e)
{
if (listBox1.InvokeRequired)
{
Action<string> d = DoAnything;
listBox1.Invoke(d, new object[] { "Item 1" });
}
else
DoAnything("Item 1");
}
void DoAnything(string itemText)
{
listBox1.Items.Remove(itemText);
}

problem with RX and web service collection loading wp7

I'm beginner with C# and wp7 platform and I have some problem with good idea to get request from web service.
I made webservice in PHP (nusoap - WSDL) and everything is working fine in "normal" using.
Now I have ObservableCollection saved in IsolatedStorage with I load when Page is open (List of watched stacks exchange). Then I want to refresh data for every item from web service.
I don't know whether this is a good idea.
Code:
private GPWWebservicePortTypeClient client = new GPWWebservicePortTypeClient();
private ObservableCollection<WebServiceClass.ItemGetValues> StoredStock =
new ObservableCollection<WebServiceClass.ItemGetValues>();
public const string _fileName = "listaObserwowanych.xml";
public Page()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(Page_Loaded);
client.GetLastValueCompleted +=
new EventHandler<GetLastValueCompletedEventArgs>(client_GetLastValueCompleted);
foreach (var itemGetValuese in App.ViewModel.Items)
{
client.GetLastValueAsync(itemGetValuese.name);
}
var o =
Observable.FromEvent<GetLastValueCompletedEventArgs(client,"GetLastValueCompleted")
.Subscribe(setList);
}
void client_GetLastValueCompleted(object sender, GetLastValueCompletedEventArgs e)
{
if (e.Error != null)
{
MessageBox.Show(Convert.ToString(e.Error));
}
else
{
ObservableCollection<WebServiceClass.ItemGetValues> ListValues =
(ObservableCollection<WebServiceClass.ItemGetValues>)
JsonConvert.DeserializeObject(e.Result,
typeof(ObservableCollection<WebServiceClass.ItemGetValues>));
StoredStock.Add(ListValues[0]);
}
}
private void setList(IEvent<GetLastValueCompletedEventArgs> ex)
{
List.ItemsSource = StoredStock;
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
App.ViewModel.LoadData();
List.ItemsSource = App.ViewModel.Items;
}
Like u see I use RX to call method client_GetLastValueCompleted add store result to auxiliary variable (StoredStock). Then refresh List in setList method, but that method is client_GetLastValueCompleted what is not soo good idea, becouse I need to run that method only when all of runned GetLastValueAsync in foreach is completed.
Second problem: becouse of async web service method StoredStock sometime have different order than App.ViewModel.Items .
Any good idea how to do that in right way?
Best regards,
Lukas
You're really mixing up a number of ways to call web services and Rx. You really need to decide on a single way and stick to it.
If you're going to use Rx, then you'll have something like this:
public Page()
{
InitializeComponent();
DataContext = App.ViewModel;
this.Loaded += new RoutedEventHandler(Page_Loaded);
}
void Page_Loaded(object sender, RoutedEventArgs e)
{
App.ViewModel.LoadData();
var storedStock =
new ObservableCollection<WebServiceClass.ItemGetValues>();
List.ItemsSource = storedStock;
var values =
Observable.Using<WebServiceClass.ItemGetValues, GPWWebservicePortTypeClient>
(() => new GPWWebservicePortTypeClient(), ws =>
{
var clientGetLastValue = Observable
.FromAsyncPattern<string, GetLastValueResponse>
(ws.BeginGetLastValue, ws.EndGetLastValue);
Func<string, WebServiceClass.ItemGetValues> deserializeFirst = r =>
((List<WebServiceClass.ItemGetValues>)JsonConvert
.DeserializeObject(r,
typeof(List<WebServiceClass.ItemGetValues>)))
.First();
return
from item in App.ViewModel.Items
from e in clientGetLastValue(item)
select deserializeFirst(e.Result);
});
values.Subscribe(storedStock.Add);
}
You'll have to get the right method call names for your web service client, but the code should roughly be right. Let me know how you go.
I corrected the code above. Should have returned the query inside the Using call rather than assign it to values.
I corrected the call to FromAsyncPattern to use the correct method names and return type from the actual web service reference class sent via email.
It should look like this:
Observable.FromAsyncPattern<string, GetLastValueResponse>
(ws.BeginGetLastValue, ws.EndGetLastValue);
If you're a beginner with C#, try to avoid RX for the time being. It is a cool technology, but if you use it without clear understanding of what is going on, it will bring more problems than solve.
Use a simple event, and when each async item arrives, locate and update the correspondent one in the stored list.

Need to set more than just a single property during Control.Invoke

I have been searching stackoverflow for ways to marshal data back from a thread to the UI thread, and have found various ways to do it in 3.5.
One of the more elegant solutions to me; although I am still learning lambdas and closures is this solution Control.Invoke with input Parameters.
I don't completely understand the code, but I do understand how to use it and it doesn't quite solve my problem.
I would like to call invoke and pass a string to another method (DisplayStatusUpdate(msg)). Any pointers would be appreciated.
private void FireEventAppender_OnMessageLogged(object sender, MessageLoggedEventArgs e)
{
DisplayStatusUpdate(e.LoggingEvent.RenderedMessage);
}
private void DisplayStatusUpdate(string text)
{
_StatusTextBox.Text = _StatusTextBox.Text + text;
_StatusTextBox.Text = String.Format("{0}\r\n", _StatusTextBox.Text);
_StatusTextBox.SelectionStart = _StatusTextBox.Text.Length - 1;
_StatusTextBox.ScrollToCaret();
}
You can do this with as many parameters as you like, for example:
private void FireEventAppender_OnMessageLogged(object sender, MessageLoggedEventArgs e)
{
DisplayStatusUpdate(e.LoggingEvent.RenderedMessage);
}
private delegate void DisplayStatusUpdateDelegate(string text);
private void DisplayStatusUpdate(string text)
{
if(InvokeRequired)
this.Invoke(new DisplayStatusUpdateDelegate(DisplayStatusUpdate), text);
else
{
_StatusTextBox.Text = _StatusTextBox.Text + text;
_StatusTextBox.Text = String.Format("{0}\r\n", _StatusTextBox.Text);
_StatusTextBox.SelectionStart = _StatusTextBox.Text.Length - 1;
_StatusTextBox.ScrollToCaret();
}
}
There is another method that I have been using in a current project that can reduct the code significantly. Details are here.
If you implement this method, you would need to:
Create the form using the AOP factory:
Form f = AOPFactory.Create<Form1>();
Application.Run(f);
And then you just decorate the event handler with the [RunInUIThread] attribute. It uses Castle's method interception model to automatically invoke if need be.
Thus, the above code becomes:
private void FireEventAppender_OnMessageLogged(object sender, MessageLoggedEventArgs e)
{
_StatusTextBox.Text = _StatusTextBox.Text + text;
_StatusTextBox.Text = String.Format("{0}\r\n", _StatusTextBox.Text);
_StatusTextBox.SelectionStart = _StatusTextBox.Text.Length - 1;
_StatusTextBox.ScrollToCaret();
}
Performance wise it seems to be comparable, slightly slower, but depending on what you are doing it may be ok, it definitely takes less code.
If you are using C# 3.5 (or later) you can use captured variables, which may simplify the code:
private void DisplayStatusUpdate(string text)
{
this.Invoke(new MethodInvoker(() =>
{
_StatusTextBox.Text = _StatusTextBox.Text + text;
_StatusTextBox.Text = String.Format("{0}\r\n", _StatusTextBox.Text);
_StatusTextBox.SelectionStart = _StatusTextBox.Text.Length - 1;
_StatusTextBox.ScrollToCaret();
}));
}
What the compiler will do behind the scenes here is to generate a class to hold the text, create a MethodInvoker delegate, and pass that delegate and an instance of the generated class to the Invoke method. In the above design this will of course do the unnecessary work of creating a delegate and calling Invoke even if the code is already running on the same thread; but I believe that a method like this should not be called that often that it would be a performance issue.
If you want to you can replace the use of MethodInvoker with the parameter-less Action delegate, or any other parameter-less delegate that returns void.

Categories

Resources