Xamarin Xaml force update interface elements - xaml

The post has been rewritten to better fit the current problem.
I have a button x:Name="selectVesselButton". On button click, it tries to establish a connection to a server, which takes a sec or two for to do. Originally, I wanted the button to be grayed out while it was downloading and deserializing the json file from the connection.
My old code (before async, and trying to update the button):
// disabling the button to prevent spam clicking.
string buttonText = selectVesselButton.Text;
selectVesselButton.IsEnabled = false;
selectVesselButton.Text = "loading...";
// retrieve data for speed page.
RetrieveData();
// redirect to next info block if build was successfull.
FocusSpeedblock();
// enabling the button again.
selectVesselButton.Text = buttonText;
selectVesselButton.IsEnabled = true;
The issue with this code was that the button visuals did not update until the RetrieveData() was finished, defeating the purpose of doing that at all. This was because the code for updating the interface and the code for downloading and deserializing the object were both on the same thread.
However, following Ivan's advice, I made the downloading and deserializing Async, which fixed this issue (more like moved it).
This works fairly well, but I am still having some trouble updating the interface automatically. I have some labels that need to be updated based on the json file output. The value of the labels update on the background, but only update visually once I interact with the labels (I.E. scrolling the scrollview they are on). Check edit 3 for more detail on that.
EDIT 3:
When the second thread is finished, it should call the UpdateSpeedLabels() and update some labels. However, they update in codebehind, without instantly updating the interface. They only update if I interact with those labels.

The preferred way of doing this on Xamarin is with data binding. As you opted out of this it is still possible.
What you need is to ensure that your long task is not running in the UI thread as it blocks it and prevent its updates. You do this by using Task.Run(() => { your task code }); . However you can't update your user interface inside the Task.Run as it is not running on the UI thread and it would crash the app, so you need to use Device.BeginInvokeOnMainThread(() => { your UI code }); inside Task.Run for that part.

Related

How to read an arbitrary folder in a Universal app?

I'm trying to learn to write Universal apps, and I'm starting out by trying to recreate another project I wrote in WinForms. I need to be able to read from log files in an arbitrary folder, and as I understand it I need to get the users permissions to access the folder. I should then store an access token so I can re-read that folder in future. By reading around I've managed to cobble together the following code:
Friend Async Function GetLogFolder() As Task(Of StorageFolder)
Dim myLogFolder As StorageFolder
If ApplicationData.Current.LocalSettings.Values.ContainsKey("LogFolder") Then
Dim sToken As String = ApplicationData.Current.LocalSettings.Values("LogFolder")
myLogFolder = StorageApplicationPermissions.FutureAccessList.GetFileAsync(sToken)
Else
Dim myFolderPicker As FolderPicker = New FolderPicker
myFolderPicker.FileTypeFilter.Add("*")
myLogFolder = Await myFolderPicker.PickSingleFolderAsync
Dim sToken As String = StorageApplicationPermissions.FutureAccessList.Add(myLogFolder)
ApplicationData.Current.LocalSettings.Values.Add("LogFolder", sToken)
End If
Return myLogFolder
End Function
But it doesn't seem to work. At this stage I have a form containing just a TextBlock and Button. Clicking the Button calls a method that will parse all the *.log files in a given folder. The first thing it does is:
Dim myFolder As StorageFolder = GetLogFolder.Result
When the code runs, and I click the button, I get a folder browser dialog shown, but then everything freezes and I have to switch to Visual Studio and hit stop. I've probably made some silly error, but I can't figure out what it is.
Any help would be much appreciated.
The problem is very likely not caused by the file access code itself, but by the way you use the asynchronous API.
Because the GetLogFolder method returns a Task of StorageFolder, you will need to await the result instead of getting it using the Result property. The reason is that the async/await pattern allows you to do I/O work on a separate thread but return control back to the UI thread when finished. What you are doing here is to call the GetLogFolder method, in which you let the user choose a folder using FolderPicker. Here is the problem - the user is presented with a folder picker while the control returns to your code and you query the Result property of the Task returned by the GetLogFolder method. Querying the Result property causes the UI thread to stop and wait until the Task is finished to get the result. Unfortunately, when the user picks the folder, the control wants to return to the UI thread to continue executing the rest of the GetLogFolder method and we have a deadlock. Result property stopped the UI thread to wait for the Task result and the Task waits for the UI thread to become available. Neither can continue so the app completely freezes.
The solution is quite simple - using the async / await keywords. You can read up more about them in VB.NET here with a clear example.
In your case the first step would be to make the button's Click handler method async and then replace the code inside by the following:
Dim myFolder As StorageFolder = Await GetLogFolder

"Invalid cross-thread access" when changing a WP8 textBlock

I'm coming from VB 6 and am semi-new to VB.NET.
I'm writing a Windows Phone 8 application. There's a grid in which I have several textBlocks that I want to dynamically display data from a file stream (that contains scanned data).
When the WP8 page opens, it automatically loads the data into the textBlocks. This works. Before I load the data from the file, I want to "reset" all textBlocks and hide them. For this I wanted to use a procedure which essentially does the following for every textBlock:
tbl1.Text = ""
tbl1.Visibility = System.Windows.Visibility.Collapsed
This works exactly one time: when the page loads. The procedure does not produce an error.
Now when I call that method again later, when I want to refresh the data shown on the page, I get the following error on the first line of code shown above:
An exception of type 'System.UnauthorizedAccessException' occurred in System.Windows.ni.dll but was not handled in user code
Additional information: Invalid cross-thread access.
I'm a bit lost now. In VB6 I was able to do whatever I wanted with my UI elements. I presume I'm making some kind of newbie mistake here?
I read somewhere about some Dispatcher thing. But that seems overly complicated to simply change a value in a textBlock to me. Is there no simple way?
The solution is indeed to use the Dispatcher.BeginInvoke method.
Dispatcher.BeginInvoke(() =>
{
tbl1.Text = ""
tbl1.Visibility = System.Windows.Visibility.Collapsed
});
The reason why you need this is because you try to access an object that depends on the UI thread from a non-UI thread.
It is probably because you are not calling the method from UI thread. Try using Dispatcher.BeginInvoke:
Dispatcher.BeginInvoke(()=>
{
tbl1.Text = "";
tbl1.Visibility = System.Windows.Visibility.Collapsed;
});

Identifying objects in IBM RFT

While executing my script in RFT, my script got failed due to the slight position change of a button. (This button's position slightly changes according to the option selected for previous combo box due to the label appearing near the button)
As there are 2 positions for this button in window, one of my script fails while other passes.
Please suggest how to identify this same object in 2 different places in RFT?
If you're alright with not using pre-mapped values and instead work with objects directly in code (which I've personally found to be extremely useful... it's allowed me to do great and wondrous things with RFT :), the following ought to work fine:
private void clickObject(String uniqueIdentifier) {
// Find object
RootTestObject root = RootTestObject.getRootTestObject();
TestObject[] matchingObjs = root.find(atProperty(".id", uniqueIdentifier));
if (matchingObjs.length > 0) {
// Click the object
((GuiTestObject) matchingObjs[0]).click();
}
// Clean-up
unregister(matchingObjs);
}
Feel free to replace ".id" with whatever property is best suited for the situation... since I work primarily with a web application, the ".id" property has worked splendidly for me.
Because the method finds the object anew each time, it'll grab the object's position wherever it's at at the time the method's called. The clean-up will also prevent any weird, horrible, and otherwise unfortunate UnregisteredObjectExceptions from cropping up.
Without looking at your pages I cannot be sure, but I think the buttons are actually two different buttons. Maybe they are generated by javascript, or they are just un-hidden after the option you select in the combobox.
If they are two different buttons (record them both and look at the recognition properties) you can either replace some properties with a regular expression or check wich button is visible/exists and then click it:
if (btn_button1.exists()) {
btn_button1.click();
} else if (btn_button2.exists()) {
btn_button1.click();
}
Here's a more complete tutorial on Object Recognition.
You can increase the tolerance of Rational Performance Tester AssureScript in the properties tab or you could set the description but hide the value. You can also make a custom code that updates the object map to prepare for this change in a java IF structure

How can I trigger the loading animation of a WinJS ListView

is there a way to trigger the loading animation of a ListView manually?
I load some data on start up from a web service and would like to display a busy indecator.
function searchData(url) {
var promise = DataService.getData(query);
promise.done(function (result) {
console.dir(result);
var bindingList = new WinJS.Binding.List(result);
sectionListView.winControl.itemDataSource = bindingList.dataSource;
});
}
this is what I do in app.onactivated
promise = WinJS.UI.processAll();
promise.done(function () {
searchData(query);
});
args.setPromise(promise);
I read something that ListView should display busy animation while waiting for a promise...
Is this true?
Or is this something I have to do manually... display and hide a div whenever needed?
Thanks for any help...
According to this thread, the progress ring will only appear if the ListView is hooked up to an asynchronous data source, while the WinJS.Binding.List is synchronous. I don't think there are any asynchronous data sources available by default, so you would have to set up a custom data source to be able to get that default progress ring. I would recommend just setting a progress ring to run when your app starts and removing it in the done block of your data promise.
You need to create your own custom List Data Source. WinJS provides the utilities to do this pretty easily. This is a good sample against the Bing web service. If you need more samples of how to write your own Data Source / Data Adapter let me know, I've written a few.

How best execute query in background to not freeze application (.NET)

My WinForm apps needs to execute complex query with significant execution time, I have no influence (about 10mins)
When query is executing user sees 'application not responding' in task manager, which is really confusing to user, also not very professional...
I believe that query shall be executed in different thread or so. Have tried some approaches but have difficulties to make it really working (execute query, force main application wait result, return back to main app, possibility to cancel execution etc)
I wonder if you have own / good working solution for that. Code samples would be also very welcome :)
Also I believe there might exist some ready to use utilities / frameworks allowing simple execution of that.
The simplest approach here would be to do that work from a BackgroundWorker. MSDN has examples for this. This then executes on a worker thread, with events for completion/error/etc. It can also support cancel, but your operation needs to be coded to be interruptable.
Another approach is the Task API in 4.0; but if you use this you'll need to get back to the UI thread (afterwards) yourself. With BackgroundWorker this is automatic (the events are raised on the UI thread).
If ExecuteQuery if the method you want to execute, you can do:
void SomeMethod() {
var thread = new Thread(ExecuteQuery);
thread.Start();
}
void ExecuteQuery() {
//Build your query here and execute it.
}
If ExecuteQuery receives some parameters, like:
void ExecuteQuery(string query) {
//...
}
You can do:
var threadStarter = () => { ExecuteQuery("SELECT * FROM [Table]"); };
var thread = new Thread(ThreadStarter);
thread.Start();
If you want to stop the execution of the background thread, avoid calling thread.Abort() method. That will kill the thread, and you do not want this, because some incosistency could appear in your database.
Instead, you can have a bool variable visible from ExecuteQuery and from outside you can set it to True when you want to stop it. Then all you have to do is check in some parts of the code inside ExecuteQuery if that variable is still True. Otherwise, do some rollback to maintain the database stable.
Be sure you set that bool variable volatile
Edit:
If you want the UI to wait from the background thread, I usually do:
Start the background thread
Start some progress bar in the UI
Disable some controls (like buttons, etc) to avoid the user to click them while the background thread is working (eg: If you're executing the thread when a user clicks a button, then you should disable that button, otherwise multiple queries will be ocurring at the same time).
After finished the thread, you can stop progress bar and enable controls again.
How to know when the thread finished? You can use Events for that. Just create an event and fire it when it finishes, and do whatever you want inside the event handler...
Be sure you're accessing correctly to UI controls from the background thread, otherwise it will give you an error.
If you are new to threads and task is simple (as it seems), you should try to use standard background worker component.