Cannot await 'void' error in windows phone - c#

I am stuck in this problem. I am creating a Windows Phone application. Here is the code.
private async void btn_signup_Click(object sender, RoutedEventArgs e)
{
obj = new ServiceReference2.Service1Client();
if (!txt_id.Text.Equals("") && !txt_name.Text.Equals("") && !txt_password.Equals(""))
{
user r = new user();
r.ID = txt_id.Text;
r.FULLNAME = txt_name.Text;
r.PASSWORD = txt_password.Text;
var g = await obj.GetDataAsync(r);
string message = g;
if (message.Equals("done"))
{
lbl_show.Text = "you have signed up !! Hurrah";
NavigationService.Navigate(new Uri("/mainmenu.xaml", UriKind.Relative));
}
else
{
lbl_show.Text = " Please fill all the field.Enter again";
}
}
}
I am getting this error "cannot await void". I am using WCF service to access the db.
Please guide me with the appropriate solution.

GetDataAsync is not a TAP method; it is an EAP method.
Try to re-create the WCF proxy and tell it to create TAP asynchronous methods. If Visual Studio doesn't give you that option, then see if the proxy has Begin*/End* methods that you can wrap into a TAP method.
If nothing else, you can wrap the EAP method/event into a TAP method.

Related

C# - UWP AppInfo throws NotImplementedException

I'm developing a C# WinForms app, using the UWP API. I'm attempting to read notifications programatically, and I have succeeded so far. However, whenever I call AppInfo from the UserNotification class, I get a NotImplementedException, no matter what property I read from AppInfo.
Does anyone have any suggestions?
I have only been able to find 1 answer to this question and it's not very useful, and also a few years old. This is a major roadblock in my project, any help is massively appreciated!
Thank you in advance.
EDIT
Here's my code.
try {
this.source = notification.AppInfo.DisplayInfo.DisplayName;
} catch(NotImplementedException e) {
this.source = "Unspecified";
}
NotificationBinding binding = notification.Notification.Visual.GetBinding(KnownNotificationBindings.ToastGeneric);
if (binding != null) {
Console.WriteLine(binding.GetTextElements()[1]);
this.title = binding.GetTextElements().FirstOrDefault()?.Text;
this.body = string.Join("\n", binding.GetTextElements().Skip(1).Select(t => t.Text));
}
Init();
I'm using the code from the examples in the docs.
UWP AppInfo throws NotImplementedException
Based on the exception message, it looks like notification.AppInfo.DisplayInfo has not
been implemented for WinForm platform. For this scenario, we have a workaround for getting AppInfo with [AppDiagnosticInfo][1] api. Please refer the following code
var list = await AppDiagnosticInfo.RequestInfoAsync();
var currentPackage = list.Where(o => o.AppInfo.PackageFamilyName == Package.Current.Id.FamilyName).FirstOrDefault();
if (currentPackage != null)
{
AppInfo currentAppInfo = currentPackage.AppInfo;
var display = currentAppInfo.DisplayInfo;
}
private async Task<AppDisplayInfo> GetDisplayInfo()
{
var list = await AppDiagnosticInfo.RequestInfoAsync();
var currentPackage = list.FirstOrDefault(o => o.AppInfo.PackageFamilyName == Package.Current.Id.FamilyName);
if (currentPackage != null)
{
var currentAppInfo = currentPackage.AppInfo;
var display = currentAppInfo.DisplayInfo;
return display;
}
return null;
}

How do you call a method from a UI thread?

I am trying to access the Microsoft Store from a multi-threaded program. The program itself work well - no problems there, but the method
Windows.Foundation.IAsyncOperation<StorePurchaseResult> purchase = product.RequestPurchaseAsync();
throws the exception:
"Invalid window handle.\r\n\r\nThis function must be called from a UI
thread"
My code is as follows...
private void testButton_Click(object sender, EventArgs e)
{
//Dispatcher dispUI = Dispatcher.CurrentDispatcher;
//dispUI.BeginInvoke((ThreadStart)delegate ()
//{
// _ = SetStore();
//});
//Dispatcher.BeginInvoke(new Action(TestStuff));
_ = SetStore();
}
[ComImport]
[Guid("4AEEEC08-7C92-4456-A0D6-1B675C7AC005")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
private interface IInitializeWithWindow
{
void Initialize(IntPtr hwnd);
}
private async Task SetStore()
{
try
{
StoreContext theStore = StoreContext.GetDefault();
// "Unable to cast object of type 'Windows.Services.Store.StoreContext' to type 'IInitializeWithWindow'."
// IInitializeWithWindow initWindow = (IInitializeWithWindow)(object)theStore;
// initWindow.Initialize(System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle);
StoreProductResult app = await theStore.GetStoreProductForCurrentAppAsync();
// This works...
StoreProduct product = app.Product;
string title = product.Title;
string price = product.Price.FormattedPrice;
// This works...
StoreAppLicense license = await theStore.GetAppLicenseAsync();
bool trial = license.IsTrial;
bool full = license.IsActive;
// "Invalid window handle.\r\n\r\nThis function must be called from a UI thread"
StorePurchaseResult result = await theStore.RequestPurchaseAsync("9NRFBVGVGW8K");
// "Invalid window handle.\r\n\r\nThis function must be called from a UI thread"
// Windows.Foundation.IAsyncOperation<StorePurchaseResult> purchase = product.RequestPurchaseAsync();
}
catch (Exception e)
{
int a = 1;
}
}
I have associated the VS2019 UWP installer project with the store, which I figure is why the other methods return the right answers without needing to cast the store object with IInitializeWithWindow (which also throws an error, but which bypassing seems to let the code work).
I figure I have to tap into the UI thread somehow - go no idea how. Various examples from all over the place don't seem to work for me. Can anyone help me?
EDIT: This is a .Net program with a UWP wrapper creating a MSIX package.
For UWP, you need to use the following bit of code to call to the UI thread:
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => {
//UI code here
});
Try following, It works for me for .net 6 wpf app
WinRT.Interop.InitializeWithWindow.Initialize(storeContext, new WindowInteropHelper(window).Handle);

UWP FolderPicker window opens but is frozen

The basic idea is I have a UWP app pulling user data from a json file saved locally, and at various times it may pull that full list of objects from the file, but it always checks that the user has set the location for the data, and if not, prompts via a FolderPicker for the user to set the location. In this case, I have combobox that helps filter the objects after selecting a criteria and entering text.
Here's the call stack:
UWPMiniatures.exe!UWPMiniatures.Data.MiniDAL.SetSaveFolder() Line 98 C# Symbols loaded.
UWPMiniatures.exe!UWPMiniatures.Data.MiniDAL.LoadAllAsync() Line 71 C# Symbols loaded.
UWPMiniatures.exe!UWPMiniatures.Data.MiniDataService.Load() Line 36 C# Symbols loaded.
UWPMiniatures.exe!UWPMiniatures.MainPage.FilterGridView(string submission) Line 156 C# Symbols loaded.
UWPMiniatures.exe!UWPMiniatures.MainPage.SearchIcon_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e) Line 95 C# Symbols loaded.
So, working backwords, the FolderPicker is being called here:
private async Task SetSaveFolder()
{
if(!StorageApplicationPermissions.FutureAccessList.ContainsItem("PickedFolderToken"))
{
FolderPicker folderPicker = new FolderPicker();
folderPicker.SuggestedStartLocation = PickerLocationId.Desktop;
folderPicker.FileTypeFilter.Add("*");
folderPicker.CommitButtonText = "Pick A Folder To Save Your Data";
StorageFolder folder = await folderPicker.PickSingleFolderAsync();
if (folder != null)
{
// Application now has read/write access to all contents in the picked folder (including other sub-folder contents)
StorageApplicationPermissions.FutureAccessList.AddOrReplace("PickedFolderToken", folder);
var userFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("PickedFolderToken");
var file = await userFolder.CreateFileAsync("AllMinisList.json",CreationCollisionOption.OpenIfExists);
var imagefolder = await userFolder.CreateFolderAsync("Images");
}
}
}
The folder picker dialog opens, with a blinking cursor next to Folder:, but nothing happens when I click anywhere, nor can i type in Folder: textbox. Now, putting this identical code in a new project and calling it in response to a click event works fine: Dialog opens, I make a new folder or pick an existing one, it gets added to future access list. Not sure how to else to troubleshoot this but the problem seems to lie out side the actual code calling the FolderPicker.
here is the code for the other calling function
private void SearchIcon_Click(object sender, RoutedEventArgs e)
{
FilterGridView(SearchTextBox.Text);
SearchTextBox.Text = "";
}
private async void FilterGridView(string submission)
{
var selected = FilterComboBox.SelectedValue;
miniDS = new MiniDataService();
if(selected.ToString()=="All")
{
MiniList.Clear();
List<Miniature> fullList = await miniDS.Load();
fullList.ForEach(m => MiniList.Add(m));
}
else if (selected.ToString() == "Quantity")
{
List<Miniature> fullList = await miniDS.Load();
var templist = fullList.AsQueryable()
.Where($"{selected} = #0", submission); ;
MiniList.Clear();
templist.ToList<Miniature>()
.ForEach(m => MiniList.Add(m));
}
else
{
List<Miniature> fullList = await miniDS.Load();
var templist = fullList.AsQueryable()
.Where($"{selected}.StartsWith(#0)", submission);
MiniList.Clear();
templist.ToList<Miniature>()
.ForEach(m => MiniList.Add(m));
}
}
MiniDataService and MiniDal don't do much here other than pass the call along.
Any ideas where I can look to troubleshoot this?
UPDATE: Some additional info, I copied the code from SetSaveFolder() directly into a new event handler for a button, clicked it, I get FolderPicker, functions perfectly. But thats not at all the functionality needed. I need it to be called, directly or indirectly from my Data Service. So here's where its created:
public sealed partial class MainPage : Page
{
/// <summary>
/// MiniList is the list of minis currently being displayed
/// </summary>
private ObservableCollection<Miniature> MiniList;
private MiniDataService miniDS;
private List<string> FilterComboList;
private Miniature NewMini;
public MainPage()
{
this.InitializeComponent();
miniDS = new MiniDataService();
MiniList = new ObservableCollection<Miniature>();
FilterComboList = PopulateFilterCombo();
NewMini = new Miniature();
MyFrame.Navigate(typeof(MiniListPage), MiniList);
}
...
So the problem seems to have something to do with the fact that FolderPicker is being called from this "static" object. Is this a thread issue? I thought in UWP I am always on the UI threadm and since at the top level an event handler is calling folderPicker I can't understand why the UI seems locked.
So i think I figured it out, though I have no idea why this happened. If anyone can clue me in, id appreciate it.
So from the call List<Miniature> fullList = await miniDS.Load();
Here's that method:
public async Task<List<Miniature>> Load()
{
return await minidal.LoadAllAsync();
}
public async Task<List<Miniature>> LoadAllAsync()
{
List<Miniature> MiniCollection = new List<Miniature>();
if (StorageApplicationPermissions.FutureAccessList.ContainsItem("PickedFolderToken"))
{
try
{
var userFolder = await StorageApplicationPermissions.FutureAccessList.GetFolderAsync("PickedFolderToken");
var file = await userFolder.GetFileAsync("AllMinisList.json");
var data = await file.OpenReadAsync();
using (StreamReader stream = new StreamReader(data.AsStream()))
{
string text = stream.ReadToEnd();
MiniCollection = JsonConvert.DeserializeObject<List<Miniature>>(text);
}
}
catch(Exception e)
{
throw e;
}
}
else
{
SetSaveFolder().Wait();
return MiniCollection;
}
return MiniCollection;
}
So the problem was right here:
SetSaveFolder().Wait();
When I replace that with
await SetSaveFolder();
it works fine. I can click in the folderPicker, and it does what it's supposed to. I guess I though .Wait() was used when you aren't return anything other than but it seems there is more too it than that!

Return string from Web API DownloadCompleteAsync

I am developing an Windows Phone Application and I am stuck at a part.
My project is in c#/xaml - VS2013.
Problem :
I have a listpicker (Name - UserPicker) which is list of all user's names. Now I Want to get the UserID from the database for that UserName. I have implemented Web Api and I am using Json for deserialization.
But I am not able to return the String from DownloadCompleted event.
Code:
string usid = "";
selecteduser = (string)UserPicker.SelectedItem;
string uri = "http://localhost:1361/api/user";
WebClient client = new WebClient();
client.Headers["Accept"] = "application/json";
client.DownloadStringAsync(new Uri(uri));
//client.DownloadStringCompleted += client_DownloadStringCompleted;
client.DownloadStringCompleted += (s1, e1) =>
{
//var data = JsonConvert.DeserializeObject<Chore[]>(e1.Result.ToString());
//MessageBox.Show(data.ToString());
var user = JsonConvert.DeserializeObject<User[]>(e1.Result.ToString());
foreach (User u in user)
{
if (u.UName == selecteduser)
{
usid = u.UserID;
}
//result.Add(c);
return usid;
}
//return usid
};
I want to return the UserID of the selected user. But Its Giving me following errors.
Since 'System.Net.DownloadStringCompletedEventHandler' returns void, a return keyword must not be followed by an object expression
Cannot convert lambda expression to delegate type 'System.Net.DownloadStringCompletedEventHandler' because some of the return types in the block are not implicitly convertible to the delegate return type
If you check source code of DownloadStringCompletedEventHandler you will see that it is implemented like that:
public delegate void DownloadStringCompletedEventHandler(
object sender, DownloadStringCompletedEventArgs e);
That means that you can't return any data from it. You probably have some method that does something with selected user id. You will need to call this method from event handler. So if this method is named HandleSelectedUserId, then code might look like that:
client.DownloadStringCompleted += (sender, e) =>
{
string selectedUserId = null;
var users = JsonConvert.DeserializeObject<User[]>(e.Result.ToString());
foreach (User user in users)
{
if (user.UName == selecteduser)
{
selectedUserId = user.UserID;
break;
}
}
HandleSelectedUserId(selectedUserId);
};
client.DownloadStringAsync(new Uri("http://some.url"));
It's also a good idea to add event handler for DownloadStringCompleted event before you call DownloadStringAsync method.

A reusable method for confirms in WinRT / Windows Store, using callbacks?

I've got the following long winded code for doing a confirm dialog in WinRT
IAsyncOperation<IUICommand> asyncCommand = null;
var messageDialog = new MessageDialog("Are you sure you want to delete this file?", "Delete File");
// Add commands and set their callbacks
UICommand delete = new UICommand("Delete");
UICommand cancel = new UICommand("Cancel");
messageDialog.Commands.Add(delete);
messageDialog.Commands.Add(cancel);
messageDialog.DefaultCommandIndex = 1;
IUICommand response = await messageDialog.ShowAsync();
if (response == delete)
{
// delete file
}
Ok, it's not that long winded, but I'd love if there was some way to put it into a reusable method. This is what I have so far.
public void Confirm(String message, string title, string proceedButtonText, string cancelButtonText)
{
IAsyncOperation<IUICommand> asyncCommand = null;
var messageDialog = new MessageDialog(message, title);
// Add commands and set their callbacks
UICommand proceed = new UICommand(proceedButtonText);
UICommand cancel = new UICommand(cancelButtonText);
messageDialog.Commands.Add(proceed );
messageDialog.Commands.Add(cancel);
messageDialog.DefaultCommandIndex = 1;
IUICommand response = await messageDialog.ShowAsync();
if (response == proceed)
{
// how do I pass my function in here?
}
}
I can figure out passing the message, button names etc - but how do I pass my code / function for delete in there? I guess my question is how do I do a "callback" to run some code?
I've accepted kiewic's answer as he pointed me in the right direction. However, I thought I'd share the full code here as an answer, in case anyone else wants to use it.
private async Task<IUICommand> Confirm(string message, string title, UICommand proceed, UICommand cancel, uint defaultCommandIndex = 1)
{
var messageDialog = new MessageDialog(message, title);
// Add commands and set their callbacks
messageDialog.Commands.Add(proceed);
messageDialog.Commands.Add(cancel);
messageDialog.DefaultCommandIndex = defaultCommandIndex;
return await messageDialog.ShowAsync();
}
Call confirm like this:
await Confirm("Are you sure you want to delete this file?", "Delete File",
new UICommand("Delete", async (command) => {
// put your "delete" code here
}), new UICommand("Cancel"));
You could further extend this by passing it a collection of UICommand objects instead - this would allow dialogs with more than two options
While I was at it I also wrote an alert method which saves some code when displaying a messaging dialogue.
private async Task<IUICommand> Alert(string message, string title = "Error")
{
var messageDialog = new MessageDialog(message, title);
return await messageDialog.ShowAsync();
}
If you come from a web / js background like me, you might find these useful ;)
Use an Action delegate, check sample here: https://msdn.microsoft.com/en-us/library/018hxwa8(v=vs.110).aspx

Categories