I am trying to make live tile which uses data from DownloadStringAsync method.
protected override void OnInvoke(ScheduledTask task){
WebClient web = new WebClient();
web.DownloadStringAsync(new Uri("website"));
web.DownloadStringCompleted += web_DownloadStringCompleted;
StandardTileData data = new StandardTileData();
ShellTile tile = ShellTile.ActiveTiles.First();
data.BackContent = string;
tile.Update(data);
}
void web_DownloadStringCompleted(object sender,
DownloadStringCompletedEventArgs e)
{
string=e.result ;
} // example
string is returning null all the time. I think it is because of async operation. Somehow if I can make it sync maybe it can work. any ideas ? thanks
You have a Race Condition Since the download operation is asynchronous, the 'string' variable (which should not compile BTW) will not necessary be updated when you will read it's value to set the BackContent.
Try this with the Async/Await keywords:
protected async override void OnInvoke(ScheduledTask task)
{
var web = new Webclient();
var result = await web.DownloadStringTaskAsync(new Uri("website"));
StandardTileData data = new StandardTileData();
ShellTile tile = ShellTile.ActiveTiles.First();
data.BackContent = result;
tile.Update(data);
}
If you can't use DownloadStringTaskAsync in your WP8 App, then try using TaskCompletionSource to accomplish the same thing, as exampled in this post .
protected async override void OnInvoke(ScheduledTask task)
{
var result = await DownloadStringTaskAsync (new Uri("website"));
StandardTileData data = new StandardTileData();
ShellTile tile = ShellTile.ActiveTiles.First();
data.BackContent = result;
tile.Update(data);
}
public Task<string> DownloadStringTaskAsync(Uri address)
{
var tcs = new TaskCompletionSource<string>();
var client = new WebClient();
client.DownloadStringCompleted += (s, e) =>
{
if (e.Error == null)
{
tcs.SetResult(e.Result);
}
else
{
tcs.SetException(e.Error);
}
};
client.DownloadStringAsync(address);
return tcs.Task;
}
Here are an example 1 & example 2 & example 3 from MSDN for using the Async/Await keyword with WebClient in Windows Phone 8.
Since you are using WP8, then you might need to add the Nuget package for the Async/Await keyword. just run
install-package Microsoft.Bcl.Async
In the Package Manager Console. Or use Nuget GUI to download it (search for 'async')
Related
I am working on a NFC reader project based on Windows 10 IoT running on a Rasperry PI 3.
I use the library Mfrc522lib.cs found here: RFID RC522 Raspberry PI 2 Windows IOT.
I use an async task to wait for the card. It scans perfect the first time, but when I start the task again (for test puprose with button).
I get this:
Pin ' is currently opened in an incompatible sharing mode. Make sure this pin is not already in use by this application or another Application
Any idea?
public MainPage()
{
this.InitializeComponent();
startNFC();
}
public void startNFC()
{
var read = ReadNFCAsync();
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
this.serial.Text = "Klar for å lese kortet ditt";
this.statusline.Fill = new SolidColorBrush(Colors.Green);
});
read.ContinueWith(prev => {
Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
() =>
{
// Your UI update code goes here!
this.serial.Text = prev.Result.ToString();
this.statusline.Fill = new SolidColorBrush(Colors.Orange);
});
});
}
public static async Task<String> ReadNFCAsync()
{
await Task.Delay(1000);
var mfrc = new Mfrc522();
await mfrc.InitIO();
while (true)
{
if (mfrc.IsTagPresent())
{
var uid = mfrc.ReadUid();
var serial= uid.ToString();
mfrc.HaltTag();
return serial;
}
}
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
startNFC();
}
This issue due to initializing GPIO pin is in use. Because every time you click the button the following line will be executed:
await mfrc.InitIO();
To solve this problem you can edit your code like this:
private Mfrc522 mfrc = new Mfrc522();
public static bool IsGpioInitialized = false;
public async Task ReadNFCAsync()
{
if (!IsGpioInitialized)
{
await mfrc.InitIO();
IsGpioInitialized = true;
}
}
I use Xamarin Auth to authenticate with OneDrive in my android app. I assume this would work, but I have the issue that when the activity for the login prompt is opened the programm will just continue and not wait for the auth to finish.
How can I wait until it's closed or wrap this in a other way async?
Code:
private IDictionary<string, string> authenticationResponseValues;
protected override async Task<AccountSession> GetAuthenticationResultAsync()
{
await Task.Run(() => ShowWebView());
return new AccountSession(authenticationResponseValues, this.ServiceInfo.AppId, AccountType.MicrosoftAccount)
{
CanSignOut = true
};
}
private void ShowWebView()
{
var auth = new OAuth2Authenticator(
clientId: MSA_CLIENT_ID,
scope: string.Join(",", scopes),
authorizeUrl: new Uri(GetAuthorizeUrl()),
redirectUrl: new Uri(RETURN_URL));
auth.Completed += SetAccountInfos;
var intent = auth.GetUI(Application.Context);
intent.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(intent);
}
private void SetAccountInfos(object sender, AuthenticatorCompletedEventArgs eventArgs)
{
if (eventArgs.IsAuthenticated)
{
Debug.WriteLine(eventArgs);
Debug.WriteLine(eventArgs.Account == null ? "IS NULL" : "IS NOT NULL");
if (eventArgs.Account != null)
{
OAuthErrorHandler.ThrowIfError(eventArgs.Account.Properties);
authenticationResponseValues = eventArgs.Account.Properties;
}
}
}
I dont think using async tactic is reasonable, because app runs before login result returns.
Try to use sync way. Make a login page. If success, then switch to your real app.
I found a solution. Here my code:
await ShowWebView();
return new AccountSession(authenticationResponseValues, ServiceInfo.AppId,
AccountType.MicrosoftAccount)
{
CanSignOut = true
};
private Task<bool> ShowWebView()
{
var tcs = new TaskCompletionSource<bool>();
var auth = new OAuth2Authenticator(OneDriveAuthenticationConstants.MSA_CLIENT_ID, string.Join(",", OneDriveAuthenticationConstants.Scopes), new Uri(GetAuthorizeUrl()),
new Uri(OneDriveAuthenticationConstants.RETURN_URL));
auth.Completed += (sender, eventArgs) =>
{
if (eventArgs.IsAuthenticated)
{
OAuthErrorHandler.ThrowIfError(eventArgs.Account.Properties);
authenticationResponseValues = eventArgs.Account.Properties;
tcs.SetResult(true);
}
};
var intent = auth.GetUI(Application.Context);
intent.SetFlags(ActivityFlags.NewTask);
Application.Context.StartActivity(intent);
return tcs.Task;
}
And the link to the class in the repo: https://github.com/Apply-Solutions/MoneyManager/blob/master/Src/MoneyManager.Droid/Src/AndroidAuthenticationProvider.cs
I'm trying to get the current user's network download speed. After hitting a dead end with NetworkInterfaces and all I tried a solution I found online. I edited it a bit and it works great but it's not asynchronous.
public static void GetDownloadSpeed(this Label lbl)
{
double[] speeds = new double[5];
for (int i = 0; i < 5; i++)
{
int fileSize = 407; //Size of File in KB.
WebClient client = new WebClient();
DateTime startTime = DateTime.Now;
if (!Directory.Exists($"{CurrentDir}/tmp/speedtest"))
Directory.CreateDirectory($"{CurrentDir}/tmp/speedtest");
client.DownloadFile(new Uri("https://ajax.googleapis.com/ajax/libs/threejs/r69/three.min.js"), "/tmp/speedtest/three.min.js");
DateTime endTime = DateTime.Now;
speeds[i] = Math.Round((fileSize / (endTime - startTime).TotalSeconds));
}
lbl.Text = string.Format("{0}KB/s", speeds.Average());
}
That function is called within a timer at an interval of 2 minutes.
MyLbl.GetDownloadSpeed()
I've tried using WebClient.DownloadFileAsync but that just shows the unlimited symbol.My next try would be to use HttpClient but before I go on does anyone have a recommended way of getting the current users download speed asynchronously (without lagging the main GUI thread)?
As it was suggested you could make an async version of GetDownloadSpeed():
async void GetDownloadSpeedAsync(this Label lbl, Uri address, int numberOfTests)
{
string directoryName = #"C:\Work\Test\speedTest";
string fileName = "tmp.dat";
if (!Directory.Exists(directoryName))
Directory.CreateDirectory(directoryName);
Stopwatch timer = new Stopwatch();
timer.Start();
for (int i = 0; i < numberOfTests; ++i)
{
using (WebClient client = new WebClient())
{
await client.DownloadFileTaskAsync(address, Path.Combine(directoryName, fileName), CancellationToken.None);
}
}
lbl.Text == Convert.ToString(timer.Elapsed.TotalSeconds / numberOfTests);
}
WebClient class being relatively old does not have awaitable DownloadFileAsync().
EDITED
As it was correctly pointed out WebClient in fact has a task-based async method DownloadFileTaskAsync(), which i advise to use. The code below can still help addressing the case when async method returning Task is not provided.
We can fix it with the help of TaskCompletionSource<T>:
public static class WebClientExtensions
{
public static Task DownloadFileAwaitableAsync(this WebClient instance, Uri address,
string fileName, CancellationToken cancellationToken)
{
TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();
// Subscribe for completion event
instance.DownloadFileCompleted += instance_DownloadFileCompleted;
// Setup cancellation
var cancellationRegistration = cancellationToken.CanBeCanceled ? (IDisposable)cancellationToken.Register(() => { instance.CancelAsync(); }) : null;
// Initiate asyncronous download
instance.DownloadFileAsync(address, fileName, Tuple.Create(tcs, cancellationRegistration));
return tcs.Task;
}
static void instance_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
((WebClient)sender).DownloadDataCompleted -= instance_DownloadFileCompleted;
var data = (Tuple<TaskCompletionSource<object>, IDisposable>)e.UserState;
if (data.Item2 != null) data.Item2.Dispose();
var tcs = data.Item1;
if (e.Cancelled)
{
tcs.TrySetCanceled();
}
else if (e.Error != null)
{
tcs.TrySetException(e.Error);
}
else
{
tcs.TrySetResult(null);
}
}
}
Try `await Task.Run(()=> { //your code });
Edit: #JustDevInc I still think you should use DownloadAsync. Task.Run(delegate) creates a new thread and you might want to avoid that. If you want, post some of your old code so we can try to fix it.
Edit: The first solution turned out to be the only one of the two working. DownloadFileAsync doesn't return task, so can't it awaited.
I am trying to operate a flashlight app through TorchControl Class in Windows Phone application:
Here is my code
private static async Task<DeviceInformation> GetCameraID(Windows.Devices.Enumeration.Panel desiredCamera)
{
DeviceInformation deviceID = (await DeviceInformation.FindAllAsync(DeviceClass.VideoCapture))
.FirstOrDefault(x => x.EnclosureLocation != null && x.EnclosureLocation.Panel == desiredCamera);
if (deviceID != null) return deviceID;
else throw new Exception(string.Format("Camera {0} doesn't exist", desiredCamera));
}
async private void Button_Click(object sender, RoutedEventArgs e)
{
var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);
var mediaDev = new MediaCapture();
await mediaDev.InitializeAsync(new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.VideoPreview,
AudioDeviceId = String.Empty,
VideoDeviceId = cameraID.Id
});
var videoDev = mediaDev.VideoDeviceController;
var tc = videoDev.TorchControl;
if (tc.Supported)
tc.Enabled = true;
mediaDev.Dispose();
}
But the problem is that the app crashes everytime i click on the button second time. I have been told to use the mediaDev.Dispose() method but it is also not working.
Here's the exception:
A first chance exception of type 'System.Exception' occurred in
mscorlib.ni.dll WinRT information: The text associated with this error
code could not be found.
This is showing while the text in "initializeasync" is highlighted
MediaCapture will throw exception when it is re-initialized. To solve this issue, Just make sure you do not initialize MediaCapture twice when you navigate back to Camera page, or when you click the camera button.
MediaCapture mediacapture = new MediaCapture();
bool initialized;
protected async override void OnNavigatedTo(NavigationEventArgs e)
{
if (initialized == false)
{
var cameraID = await GetCameraID(Windows.Devices.Enumeration.Panel.Back);
await mediacapture.InitializeAsync(new MediaCaptureInitializationSettings
{
StreamingCaptureMode = StreamingCaptureMode.Video,
PhotoCaptureSource = PhotoCaptureSource.Photo,
AudioDeviceId = string.Empty,
VideoDeviceId = cameraID.Id
});
}
//Selecting Maximum resolution for Video Preview
var maxPreviewResolution = mediacapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.VideoPreview).Aggregate((i1, i2) => (i1 as VideoEncodingProperties).Height > (i2 as VideoEncodingProperties).Height ? i1 : i2);
//Selecting 4rd resolution setting
var selectedPhotoResolution = mediacapture.VideoDeviceController.GetAvailableMediaStreamProperties(MediaStreamType.Photo).ElementAt(3);
await mediacapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.Photo, selectedPhotoResolution);
await mediacapture.VideoDeviceController.SetMediaStreamPropertiesAsync(MediaStreamType.VideoPreview, maxPreviewResolution);
// in my .xaml <CaptureElement Name="viewfinder" />
viewfinder.Source = mediacapture;
mediacapture.SetPreviewRotation(VideoRotation.Clockwise90Degrees);
await mediacapture.StartPreviewAsync();
initialized = true;
}
Also, make sure the camera stops previewing before you navigate to other page, or before camera starts preview again. There's no need to dispose MediaCapture.
private async void GoBack_Click(object sender, RoutedEventArgs e)
{
await mediacapture.StopPreviewAsync();
this.Frame.Navigate(typeof(MainPage));
//Not needed
//mediacapture.Dispose();
}
GetCameraID method credit to Romasz's blog. http://www.romasz.net/how-to-take-a-photo-in-windows-runtime/
This issue may be related to multithreading: using the defaults (ie not changing the SynchronizationContext) calls to await will continue methods on another thread, something which is not always supported by graphics and media libraries (I have firsthand experience with SFML, WPF, and AutoCAD getting very crash-happy, to name a few). While the presence of an InitializeAsync method indicates otherwise, make sure disposal doesn't need to happen on the main thread or such.
I have a windows phone 7 app with following code
ServiceReference1.SMSWarriorServiceSoapClient ws = new ServiceReference1.SMSWarriorServiceSoapClient();
ws.BalanceCompleted += new EventHandler<ServiceReference1.BalanceCompletedEventArgs>(ws_BalanceCompleted);
ws.BalanceAsync(textBox1.Text, textBox2.Password);
Now i want to make it also for Windows 8 store app. I try this
var client = new ServiceReference1.SMSWarriorServiceSoapClient() ;
var result = client.BalanceAsync("user", "pass");
resultDetails.Text = result.ToString ;
but with no luck
I also try the Await but I don't know how to use it
If you are calling the web service method from an event handle then use this.
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
var client = new ServiceReference1.SMSWarriorServiceSoapClient();
var result = await client.BalanceAsync("user", "pass");
resultDetails.Text = result.ToString();
}
If you are calling the web service method from a method then use this.
private async Task ServiceCall()
{
var client = new ServiceReference1.SMSWarriorServiceSoapClient();
var result = await client.BalanceAsync("user", "pass");
resultDetails.Text = result.ToString();
}
Ensure you call method ServiceCall() with await keyword.
if u use await then u must use async keyword or use Task
var client = new ServiceReference1.SMSWarriorServiceSoapClient() ;
var result = await client.BalanceAsync("user", "pass");
resultDetails.Text = result.ToString ;
for example:
// Put the keyword, async on the declaration of the event handler.
private async void Button_Click_1(object sender, RoutedEventArgs e)
{
var respose=await <some async operation >
}