Await execution of base method in derived event handler - c#

I am trying to get file property in derived custom control. The code is follows:
public partial class ControlBase : UserControl {
public ControlBase() {
this.InitializeComponent();
//Buttons
PickFileButton.Click += pickFile;
}
protected virtual async void pickFile(object sender, RoutedEventArgs e) {
var picker = new FileOpenPicker();
picker.SuggestedStartLocation = PickerLocationId.VideosLibrary;
picker.FileTypeFilter.Add(".wmv");
picker.FileTypeFilter.Add(".mp4");
var file = await picker.PickSingleFileAsync();
if (file == null) return;
inputFile = file;
}
}
public sealed partial class DerivedControl : ControlBase {
protected async override void pickFile(object sender, RoutedEventArgs e) {
base.pickFile(sender, e);
//need to pick file first
var properties = await inputFile.Properties.GetVideoPropertiesAsync();
}
How can I await picker.PickSingleFileAsync() completion? Derived implementation continues befor file has been picked. Thanks in advance!

As you cannot await on async void, i suggest you do it in a way which is awaitable:
protected virtual async void pickFile(object sender, RoutedEventArgs e)
{
await PickFileAsync();
}
protected async Task PickFileAsync()
{
var picker = new FileOpenPicker();
picker.SuggestedStartLocation = PickerLocationId.VideosLibrary;
picker.FileTypeFilter.Add(".wmv");
picker.FileTypeFilter.Add(".mp4");
var file = await picker.PickSingleFileAsync();
if (file == null) return;
inputFile = file;
}
And then inside your derived:
protected async override void pickFile(object sender, RoutedEventArgs e)
{
await base.PickFileAsync();
//need to pick file first
var properties = await inputFile.Properties.GetVideoPropertiesAsync();
}
I assume inputFile is accessible in your derived types. If not, simply return a Task<InputFile> from PickFileAsync

Maybe you lack await keyword in front of base.PickFile(sender, e) ?

Related

Events and Delegates in Xamarin forms parent and child pages

I need some help. I am new to Events and handlers and I would like to begin using events for decoupling purposes but I am confused.
I have a class where I have a list view that is populated on OnAppearing. However to prevent onAppearing to happen each time the page is clicked I load the list once and then I would like to have items to get added or deleted to the list upon being added or removed from the server through the use of events.
The ListView page is a list of my favorite newspaper article Links. When clicking on any one of these links I get redirected to a LinksDetailsPage where I pass in the selected link and then display any details associated with the link.
Anyways...
I would like to add or remove an item on the my Favorites list seamlessly. So when I click on the AddItem or RemoveItem in the LinksDetailsPage I would like the item to either remove or add to theFavoritesPage List. Before I was only relying on the OnAppearing to work its magic and update the favorites list but it would lag to remove the item from the list, so this way I hope it would remove or add as soon as the even is invoked and not when the page loads on OnAppearing. However I think I am either not invoking the event properly or my subscriber is not subscribed properly. Events and delegates have been confusing for me from the get go. On top of that my favorites list is grouped so and it's my first time working with grouped lists as well.
Check out my code:
Subscriber
My Favorites Page:
public FavoritesPage()
{
InitializeComponent();
}
protected override async void OnAppearing()
{
if (_isDataLoaded)
return;
_isDataLoaded = true;
base.OnAppearing();
await LoadFavorites();
}
private async Task LoadFavorites()
{
groups = new ObservableCollection<LinksTypeGroup<string, NewspaperLink>>();
var links = await _db.GetAllFavorites();
var linkType = await _manager.GetLinkCategories();
foreach(var type in linkType)
{
var typegroup = links.FindAll(
delegate(NewspaperLink link)
{
return link.iLinkTypeID == type.iLinkTypeID;
});
groups.Add(new LinksTypeGroup<string, NewspaperLink>(type.Title, typegroup));
MyList.GroupDisplayBinding = new Binding("GroupKey");
MyList.ItemsSource = groups;
}
}
public void Listener(FavoritesPage P)
{
P.LinkAdded += Item_Added;
P.LinkDeleted += Item_Deleted;
}
void Item_Deleted(object sender, int e)
{
Console.WriteLine("Item_Deleted");
// remove item from groups ..see code above
}
void Item_Added(object sender, int e)
{
Console.WriteLine("Item_Added");
// add to groups ..see code above
}
I am not accessing anything so far.
Publisher
LinksDetailsPage:
private NewspaperLink _link;
public event EventHandler< NewspaperLink> ItemAdded;
public event EventHandler< NewspaperLink> ItemDeleted;
public LinksDetailsPage(NewspaperLink link)
{
_link = link;
BindingContext = _link;
InitializeComponent();
}
protected override async void OnAppearing()
{
base.OnAppearing();
await LoadLink();
}
private async Task LoadLink()
{
var url = await db.ReturnRecipeLink(_link.iLinkID);
linkWebView.Source = url;
CheckifExists(_link);
}
}
void AddLink(object sender, System.EventArgs e)
{
var link = BindingContext as NewspaperLink;
db.InsertIntoMyList(_link);
ItemAdded?.Invoke(this, link);
}
void DeleteLink(object sender, System.EventArgs e)
{
var link = BindingContext as NewspaperLink;
db.DeleteFromMyList(_link);
ItemDeleted?.Invoke(this, link);
}
Can someone guide me on how to make this even process work?
Event
If want to use Events, LinksDetailsPage should be declared something like following:
public partial class LinksDetailsPage : ContentPage
{
public event EventHandler<NewspaperLink> ItemAdded;
public event EventHandler<NewspaperLink> ItemDeleted;
public LinksDetailsPage()
{
InitializeComponent();
}
protected virtual void AddLink(NewspaperLink e)
{
EventHandler<NewspaperLink> handler = ItemAdded;
if (handler != null)
{
handler(this, e);
}
}
protected virtual void DeleteLink( NewspaperLink e)
{
EventHandler<NewspaperLink> handler = ItemDeleted;
if (handler != null)
{
handler(this, e);
}
}
// Add click event
private void Add_Clicked(object sender, EventArgs e)
{
AddLink(new NewspaperLink() {link="first link" });
}
// Delete click event
private void Delete_Clicked(object sender, EventArgs e)
{
DeleteLink(new NewspaperLink() { link = "first link" });
}
}
public class NewspaperLink : EventArgs
{
public string link { get; set; }
}
Then you need to subscribe it in the ListView page when navigating to the LinksDetailsPage page:
private async void Button_Clicked(object sender, EventArgs e)
{
LinksDetailsPage detailPage = new LinksDetailsPage();
detailPage.ItemAdded += DetailGridPage_ItemAdded;
detailPage.ItemDeleted += DetailGridPage_ItemDeleted;
await Navigation.PushModalAsync(detailGridPage);
}
private void DetailGridPage_ItemDeleted(object sender, NewspaperLink e)
{
Console.WriteLine("The tlink was deleted : " + e.link);
}
private void DetailGridPage_ItemAdded(object sender, NewspaperLink e)
{
Console.WriteLine("The link was added : "+e.link);
}
Delegate
Similarly, if want to use Delegate, you only need to declare something in List Page as follows:
public partial class ListViewPage : ContentPage
{
public delegate void ItemAddedDelegate(NewspaperLink e);
public delegate void ItemDeletedDelegate(NewspaperLink e);
public ListViewPage()
{
InitializeComponent();
}
private async void Button_Clicked(object sender, EventArgs e)
{
ItemAddedDelegate itemAddedDelegate = AddMethod;
ItemDeletedDelegate itemDeletedDelegate = DeleteMethod;
DetailGridPage detailGridPage = new DetailGridPage(itemAddedDelegate, itemDeletedDelegate);
await Navigation.PushModalAsync(detailGridPage);
}
public static void AddMethod(NewspaperLink item)
{
Console.WriteLine("Add" + item.link);
}
public static void DeleteMethod(NewspaperLink link)
{
Console.WriteLine("Delete" + item.link);
}
}
Then in LinksDetailsPage, you can pass the add or delete delegate method to ListViewPage.
public partial class LinksDetailsPage : ContentPage
{
private ListViewPage.ItemAddedDelegate itemAddedDelegate;
private ListViewPage.ItemDeletedDelegate itemDeletedDelegate;
public DetailGridPage()
{
InitializeComponent();
}
public LinksDetailsPage(ListViewPage.ItemAddedDelegate itemAddedDelegate, ListViewPage.ItemDeletedDelegate itemDeletedDelegate)
{
InitializeComponent();
this.itemAddedDelegate = itemAddedDelegate;
this.itemDeletedDelegate = itemDeletedDelegate;
}
// Add click event
private void Add_Clicked(object sender, EventArgs e)
{
itemAddedDelegate(new NewspaperLink() { link = "first link" });
}
// Delete click event
private void Delete_Clicked(object sender, EventArgs e)
{
itemDeletedDelegate(new NewspaperLink() { link = "first link" });
}
}
public class NewspaperLink : EventArgs
{
public string link { get; set; }
}
MessageCenter
If using MessageCenter, it should be the best convenient method to achieve that.
Only Subscribe it in ListView page:
public ListViewPage()
{
InitializeComponent();
MessagingCenter.Subscribe<object, NewspaperLink>(this, "Add", async (sender, arg) =>
{
await DisplayAlert("Message received", "arg=" + arg.link, "OK");
});
MessagingCenter.Subscribe<object, NewspaperLink>(this, "Delete", async (sender, arg) =>
{
await DisplayAlert("Message received", "arg=" + arg.link, "OK");
});
}
And send message in LinksDetailsPage as follows:
// Add click event
private void Add_Clicked(object sender, EventArgs e)
{
NewspaperLink newspaperLink= new NewspaperLink() { link = "first link" };
MessagingCenter.Send<object, NewspaperLink>(this, "Add", newspaperLink);
}
// Delete click event
private void Delete_Clicked(object sender, EventArgs e)
{
NewspaperLink newspaperLink = new NewspaperLink() { link = "first link" };
MessagingCenter.Send<object, NewspaperLink>(this, "Delete", newspaperLink);
}

Need to return a variable from a button click method and reuse it in another method

private async void ToggleButton_Checked(object sender, RoutedEventArgs e)
{
StorageFile tempFile = await EncodeFileAsync();
......
}
private async void Save_Click(object sender, ContentDialogButtonClickEventArgs e)
{
......
}
I have tried using a global variable, but it will be empty since it awaits an async method. Awaiting it another time causes the encoding to happen once again.
Set the field after the async method has returned:
private StorageFile _tempFile;
private async void ToggleButton_Checked(object sender, RoutedEventArgs e)
{
var temp = await EncodeFileAsync();
_tempFile = temp;
......
}
private async void Save_Click(object sender, ContentDialogButtonClickEventArgs e)
{
if (_tempFile != null)
...
}

How to make async task not stall on response [duplicate]

static async void SendTweetWithSinglePicture(string message, string image)
{
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = "",
ConsumerSecret = "",
AccessToken = "",
AccessTokenSecret = ""
}
};
var context = new TwitterContext(auth);
var uploadedMedia = await context.UploadMediaAsync(File.ReadAllBytes(#image));
var mediaIds = new List<ulong> { uploadedMedia.MediaID };
await context.TweetAsync(
message,
mediaIds
);
}
protected void Page_Load(object sender, EventArgs e)
{
SendTweetWithSinglePicture("test", "path");
}
How can I call a async method on Page_Load?
The question is if you want to make the Page_Load method async or not. If so:
protected async void Page_Load(object sender, EventArgs e)
{
await SendTweetWithSinglePicture("test", "path");
}
Or if you don't want it to be async:
protected void Page_Load(object sender, EventArgs e)
{
SendTweetWithSinglePicture("test", "path").Wait();
}
This does require your async method to return Task as it always should! (except event handlers)
The problem with this might be that the method doesn't complete before rendering the page. If it has to, you'd better make the method synchronous, or register the task using Page.RegisterAsyncTask and Page.ExecuteRegisteredAsyncTasks. Effectively this will freeze the Page_Load method too.
protected void Page_Load(object sender, EventArgs e)
{
PageAsyncTask t = new PageAsyncTask(SendTweetWithSinglePicture("test", "path"));
// Register the asynchronous task.
Page.RegisterAsyncTask(t);
// Execute the register asynchronous task.
Page.ExecuteRegisteredAsyncTasks();
}
You should use PageAsyncTask. It has samples in MSDN page.
// Register the asynchronous task.
Page.RegisterAsyncTask(new PageAsyncTask(SendTweetWithSinglePicture(message, image));
// Execute the register asynchronous task.
Page.ExecuteRegisteredAsyncTasks();
as I pointed the sample and explanations on MSDN page is pretty good.
Try This :
public void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
}
public async Task LoadSomeData()
{
var clientcontacts = Client.DownloadStringTaskAsync("api/contacts");
var clienttemperature = Client.DownloadStringTaskAsync("api/temperature");
var clientlocation = Client.DownloadStringTaskAsync("api/location");
await Task.WhenAll(clientcontacts, clienttemperature, clientlocation);
var contacts = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Contact>>(await clientcontacts);
var location = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clientlocation);
var temperature = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clienttemperature);
listcontacts.DataSource = contacts;
listcontacts.DataBind();
Temparature.Text = temperature;
Location.Text = location;
}

Call Async Method in Page_Load

static async void SendTweetWithSinglePicture(string message, string image)
{
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore
{
ConsumerKey = "",
ConsumerSecret = "",
AccessToken = "",
AccessTokenSecret = ""
}
};
var context = new TwitterContext(auth);
var uploadedMedia = await context.UploadMediaAsync(File.ReadAllBytes(#image));
var mediaIds = new List<ulong> { uploadedMedia.MediaID };
await context.TweetAsync(
message,
mediaIds
);
}
protected void Page_Load(object sender, EventArgs e)
{
SendTweetWithSinglePicture("test", "path");
}
How can I call a async method on Page_Load?
The question is if you want to make the Page_Load method async or not. If so:
protected async void Page_Load(object sender, EventArgs e)
{
await SendTweetWithSinglePicture("test", "path");
}
Or if you don't want it to be async:
protected void Page_Load(object sender, EventArgs e)
{
SendTweetWithSinglePicture("test", "path").Wait();
}
This does require your async method to return Task as it always should! (except event handlers)
The problem with this might be that the method doesn't complete before rendering the page. If it has to, you'd better make the method synchronous, or register the task using Page.RegisterAsyncTask and Page.ExecuteRegisteredAsyncTasks. Effectively this will freeze the Page_Load method too.
protected void Page_Load(object sender, EventArgs e)
{
PageAsyncTask t = new PageAsyncTask(SendTweetWithSinglePicture("test", "path"));
// Register the asynchronous task.
Page.RegisterAsyncTask(t);
// Execute the register asynchronous task.
Page.ExecuteRegisteredAsyncTasks();
}
You should use PageAsyncTask. It has samples in MSDN page.
// Register the asynchronous task.
Page.RegisterAsyncTask(new PageAsyncTask(SendTweetWithSinglePicture(message, image));
// Execute the register asynchronous task.
Page.ExecuteRegisteredAsyncTasks();
as I pointed the sample and explanations on MSDN page is pretty good.
Try This :
public void Page_Load(object sender, EventArgs e)
{
RegisterAsyncTask(new PageAsyncTask(LoadSomeData));
}
public async Task LoadSomeData()
{
var clientcontacts = Client.DownloadStringTaskAsync("api/contacts");
var clienttemperature = Client.DownloadStringTaskAsync("api/temperature");
var clientlocation = Client.DownloadStringTaskAsync("api/location");
await Task.WhenAll(clientcontacts, clienttemperature, clientlocation);
var contacts = Newtonsoft.Json.JsonConvert.DeserializeObject<List<Contact>>(await clientcontacts);
var location = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clientlocation);
var temperature = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(await clienttemperature);
listcontacts.DataSource = contacts;
listcontacts.DataBind();
Temparature.Text = temperature;
Location.Text = location;
}

Convert method to return a task

How can I turn the below method into the right format for returning a task items. The method stub requires a task to be used. This is my first time into async methods I am using it for the windows phone 8 like below:
private System.Threading.Tasks.Task listView_PullToRefreshRequested(object sender, EventArgs e)
{
Populatelist();
}
public async void Populatelist()
{
try
{
curoListsDal _db = new curoListsDal();
cLists = await _db.GetListsAync();
listView.ItemsSource = cLists;
}
catch (Exception ex)
{
}
}
The right format would be to return a Task instead of void in PopulateListAsync and await on that inside your event handler:
private async void PullToRefreshRequestAsync(object sender, EventArgs e)
{
await PopulateListAsync();
}
public async Task PopulateListAsync()
{
curoListsDal db = new curoListsDal();
listView.ItemsSource = await db.GetListsAsync();
}
Side note: don't swallow exceptions.

Categories

Resources