How to use the RunOnUiThread on ContentPage on Xamarin Forms - multithreading

I want to use the RunOnUiThread for Update the UI (Chart and Label) with UI Thread by Timer. I am using the ContentPage. How can I use the Add the Activity class for RunOnUiThread on Content Page ? It's not supported.
I'd like to do the following:
RunOnUiThread(() => { tvTimer.Text = Convert.ToString(CountSeconds );});
Currently I am using the
Device.BeginInvokeOnMainThread(async () => });
for update the UI but UI is stucking or not updating properly like shows count down timer per seconds.
Please help me out

The reason I think it is happening is that because you are probably doing some minor mistake and from the code that I see I cannot make that out so I will give a reference sort of thing for you to take a look on :
Define a method to be executed on the main thread:
private async void MethodOnUIThread()
{
await **something**;
//Probably your timer code
//This method does not necessarily have to be async.
}
Run the method on Main thread something like this :
Device.BeginInvokeOnMainThread(MethodOnUIThread);
Revert in case of queries or if you do not understand something

Related

MVVM Light DispatcherHelper, correct way to multithread in MVVM Light

What is the recommended way to do multithreading with MVVM Light.
I have a model which has a bool property Busy
public bool Busy
{
get { return busy_; }
set
{
Set(nameof(Busy), ref busy_, value, broadcast: true);
}
}
My view model publish the model directly for the view (the model is inherit MVVM Light's ViewModelBase), so the view binds directly to the model's busy property.
If I call the model always from the UI thread everything is good. But if I do the following in my view model so it may execute on a different thread
Task.Factory.StartNew(() =>
{
model_.SomeFunctionThatWillSetBusyDuringItsExecution();
});
Then of course Busy is set from a non UI thread and then the binding fails and the application crashes. If I happen to use the Messenger in the property setter, it seems the Messenger does not automatically dispatch the Messenger handler code to the UI thread either.
I realized there is a DispatcherHelper in MVVM Light, but for the binding it does not seem to help. If I change the property to
public bool Busy
{
get { return busy_; }
set
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
Set(nameof(Busy), ref busy_, value, broadcast: true);
});
}
}
I still get an exception and the application crash due to the binding source is not on the correct thread. So my question is simple, what is the recommended way to do multithreading like this in MVVM Light?
I did also try to use a syncronizationContext.
syncContext_.Post(() =>
{
Set(nameof(Busy), ref busy_, value, broadcast: true);
}, null);
That works if the call is always from a non UI-thread. If the call is already from the UI thread, the syncContext.Post results in that the Set() function is not called until all the code in the ViewModel method has finished. That means the busy state might not be updated correctly for the remaining code. So it is not an ideal solution.
I am thankful for help on this topic.
Instead of adding the DispatcherHelper code inside the property I added it at all places where the property was modified. Then it seems to work well.
Only problem, since one dispatch the work to the UI thread, the code in the ViewModel would not get the updated state if part of the view model method already runs on the UI thread. I found a way to force the UI thread to process its messenger queue though making sure it got the updated state of Busy. It is not the best looking solution, and it is likely to have a bad performance impact due to all context switching, but at least it works and it is a simple one liner.
Code to force the UI thread to process all messages in its queue
DispatcherHelper.UIDispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);
If there is a more optimal way to solve it then please let me know. Otherwise I will set this as the answer in a few days from now.

Parellel Task Library vs UI Thread Xamarin.Forms when constantly updating the UI

I am trying to make a stopwatch in Xamarin Forms and was wondering if I should use the native UI threading or Parallel Task Lib to constantly update the time label?
I tried to use the PT Lib, but I'm unable to get it to update my label, which makes me think that I should be using Native Threading, but I'm worry if I would be able to update the UI using a dependency service.
Is there a best practice for constantly updating the UI but still being able to execute other tasks such as button clicks?
UPDATE: I got this code below to work, but is this good practice? I am updating the time label constantly while still also bing able to press the lap buttons.
Stopwatch sw = new StopWatch();
bool inRace = false;
async void StartLapClick(object sender, System.EventArgs e)
{
if (!inRace)
{
inRace = true;
sw.Start();
updateTimer();
}
}
async void updateTimer()
{
await Task.Run(() =>
{
while(inRace)
{
string slc = sw.Elapsed.ToString();
Device.BeginInvokeOnMainThread(() =>
{
timerLbl.Text = slc;
});
Task.Delay(100).Wait();
}
});
}
No, your code has some issues (according to the Best Practices in Asynchronous Programming):
async void is bad - this will call your method in fire-and-forget fashion, you even can't get the errors from there. You should use it only for event handlers like StartLapClick, not for real methods like updateTimer
Task.Delay(100).Wait(); - Do not block on tasks, use await for this
replace the whole while loop with a simple timer, and remove the Task.Delay call
updateTimer(); - you're calling async method in synchronous fashion, which is also bad.
You have to update the UI from the UI thread. You could have a timer or something running in the background kicking out events periodically to be picked up and forwarded to the UI thread. Even if you did that, I don't know that the parallel task library is what you'd want to use. That's more focused on running many tasks... in parallel.
Try this:
Device.StartTimer(TimeSpan.FromSeconds(1.0), () => {
// Your code
};

Monotouch PerformSelector on specific thread with multiple arguments and callbacks

I've been having some issues with threading in monotouch. My app makes use of an external library which I've linked with and it works fine. Because of the nature of the app and the library I have to make all the calls to it on a single separate thread.These calls will generally be :
Random non deterministic caused by user
Every t miliseconds(around 20ms). Like an update function
After reading for a bit I decided to try out NSThread. I've managed to call the Update function by attaching an NSTimer to the thread's RunLoop and it's all working fine. The problem that I'm having now is calling other methods on the same thread. I read somewhere that using PerformSelector on the RunLoop adds the selector invocation to the RunLoop's queue and invokes it when available, which is basically exactly what I need. However the methods that I need to call :
Can have multiple paramteres
Have callbacks, which I need to invoke on the main thread, again with multiple parameters
For the multiple parameters problem I saw that NSInvocation can be a solution, but the life of me I can't figure out how to do it with monotouch and haven't found any relevant examples.
For the actuals calls that I need to make to the library, I tried doing a generic way in which I can call any function I choose via delegates on a particular thread, which sort of works until I'm hit with the multiple parameters and/or callbacks to the main thread again with multiple parameters. Should I maybe just register separate selectors for each (wrapped)function that I need to call from the library?
I'm not hellbent on using this approach, if there is a better way I'm open to it, it's just that after searching for other options I saw that they don't fit my case:
GCD(not even sure I have it in monotouch) spawns threads on it's own whenever necessary. I need a single specific thread to schedule my work on
NSInvocationQueue(which uses GCD internally from what I read) does the same thing.
pThreads, seem overkill and managing them will be a pain(not even sure I can use them in monotouch)
I'm not an iOS developer, the app works fine with monodroid where I had Runnables and Handlers which make life easier :) . Maybe I'm not looking at this the right way and there is a simple solution to this. Any input would be appreciated.
Thanks
UPDATE
I was thinking of doing something along these lines :
Have a simple wrapper :
class SelectorHandler : NSObject
{
public static Selector Selector = new Selector("apply");
private Action execute;
public SelectorHandler(Action ex)
{
this.execute = ex;
}
[Register("apply")]
private void Execute()
{
execute();
}
}
Extend NSThread
public class Daemon : NSThread
{
public void Schedule(Action action)
{
SelectorHandler handler = new SelectorHandler(action);
handler.PerformSelector(SelectorHandler.Selector, this, null, true);
}
}
Then, when I want to call something I can do it like this :
private Daemon daemon;
public void Call_Library_With_Callback(float param, Action<int> callback)
{
daemon.Schedule(() =>
{
int callbackResult = 0;
//Native library calls
//{
// Assign callback result
//}
daemon.InvokeOnMainThread(() =>
{
callback(callbackResult);
});
});
}

Portable Class Library and ObservableCollection, updating UI Thread

I'm not very experienced with this topic so forgive me if this isn't very clear.
I've created a Portable Class Library that has an ObservableCollection of Sections, and each secion has an ObservableCollection of Items.
Both of these collections are bound to the UI of separate Win8 and WP8 apps.
I'm trying to figure out the correct way to populate these collections correctly so that the UI gets updated from the PCL class.
If the class was inside the win8 project I know I could do something like Dispatcher.BeginInvoke, but this doesn't translate to the PCL, nor would I be able to reuse that in the WP8 project.
In this thread (Portable class library equivalent of Dispatcher.Invoke or Dispatcher.RunAsync) I discovered the SynchroniationContext class.
I passed in a reference to the main app's SynchroniationContext, and when I populate the sections I can do so because it's only the one object being updated:
if (SynchronizationContext.Current == _synchronizationContext)
{
// Execute the CollectionChanged event on the current thread
UpdateSections(sections);
}
else
{
// Post the CollectionChanged event on the creator thread
_synchronizationContext.Post(UpdateSections, sections);
}
However, when I try to do the same thing with articles, I have to have a reference to both the section AND the article, but the Post method only allows me to pass in a single object.
I attempted to use a lambda expression:
if (SynchronizationContext.Current == _synchronizationContext)
{
// Execute the CollectionChanged event on the current thread
section.Items.Add(item);
}
else
{
// Post the CollectionChanged event on the creator thread
_synchronizationContext.Post((e) =>
{
section.Items.Add(item);
}, null);
}
but I'm guessing this is not correct as I'm getting an error about being "marshalled for a different thread".
So where am I going wrong here? how can I update both collections correctly from the PCL so that both apps can also update their UI?
many thanks!
Hard to say without seeing the rest of the code but I doubt is has anything to do with Portable Class Libraries. It would be good to see the details about the exception (type, message and stack trace).
The way you call Post() with more than argument looks correct. What happens if you remove the if check and simply always go through SynchronizationContext.Post()?
BTW: I don't explicitly pass in the SynchronizationContext. I assume that the ViewModel is created on the UI Thread. This allows me to capture it like this:
public class MyViewModel
{
private SynchronizationContext _context = SynchronizationContext.Current;
}
I would recommend that at least in your ViewModels, all publicly observable state changes (ie property change notifications and modifications to ObservableCollections) happen on the UI thread. I’d recommend doing the same thing with your model state changes, but it might make sense to let them make changes on different threads and marshal those changes to the UI thread in your ViewModels.
To do this, of course, you need to be able to switch to the UI thread in portable code. If SynchronizationContext isn’t working for you, then just create your own abstraction for the dispatcher (ie IRunOnUIThread).
The reason you were getting the "marshalled on a different thread" error is that you weren't passing the item to add to the list as the "state" object on the Post(action, state) method.
Your code should look like this:
if (SynchronizationContext.Current == _synchronizationContext)
{
// Execute the CollectionChanged event on the current thread
section.Items.Add(item);
}
else
{
// Post the CollectionChanged event on the creator thread
_synchronizationContext.Post((e) =>
{
var item = (YourItemnType) e;
section.Items.Add(item);
}, item);
}
If you make that change, your code will work fine from a PCL.

Data binding with plugins using MEF?

I have an application that has a class named: UploadItem. The application creates uploading tasks based on information it has, for example, an upload needs to be created to upload a file to sitex.com with this the application creates a new UploadItem and adds that to an ObservableCollection, the collection is bound to a listview.
Now comes the part that I cannot solve.. I decided to change the structure so that people can create their own plugins that can upload a file, the problem lies with the fact that the UploadItem class has properties such as:
string _PercentagedDone;
public string PercentageDone
{
get { return _PercentagedDone; }
set { _PercentagedDone = value + "%"; NotifyPropertyChanged("PercentageDone"); }
}
But the plugin controls on how a file is uploaded, so how would the plugin edit the PercentageDone property that is located in the UploadItem class? If there is no way to do such a thing, then is there another way to achieve the same, i.e. showing the progress on the main GUI?
You'll want to define an interface for the plugins. Something like:
public interface IUploadPlugin
{
Task<bool> Upload(IEnumerable<Stream> files);
int Progress { get; }
}
The plugins then need to implement this interface and export themselves:
[Export(typeof(IUploadPlugin))]
public class MyUploader : IUploadPlugin, INotifyPropertyChanged
{
// ...
}
Notice that this plugin implements INotifyPropertyChanged. This is an easy way to handle updating the progress. Fire PropertyChanged on the Progress property and then databind your ProgressBar control in the main view to this property. Make sure that you fire PropertyChanged on the UI thread.
Another option would be to fire a custom event when the property changes. You could handle this event in the main view logic and update the progress.
Notice that I'm using Task for the return. This allows the caller to wait until the upload task finishes. You could use a callback instead, but with the CTP of the next version of .NET, using Task<> will allow you to use the await keyword for your async programming. Check it out here and here.

Resources