Xamarin forms what is the best of search query with API - c#

I am learning xamarin forms.
I using Azure search API to query news but sometimes the result of search is not good because of my search code. I can tap for instance "cat" but because of the delay "ca" is sent to the API.
What I woud like please :
I would like to launch automatically my search function each time the user is not tapping on search bar.
For instance lets say a user is willing to tap "tennis is a sport":
So he taps quikly on search bar and make a pause on "tennis is" => launch function on "tennis is"
Then he continues and finishs the sentence : "tennis is a sport" => launch function on "tennis is a sport"
If there is a better way of doing it, I will take.
Here is my code :
Task tasksearch = null;
int timeDelaySearch = 1000;
void OnSearcMyNews(System.Object sender, Xamarin.Forms.TextChangedEventArgs e)
{
try {
if (tasksearch == null || tasksearch.IsCompleted)
{
tasksearch = Task.Run(async () =>
{
await Task.Delay(timeDelaySearch);
Device.BeginInvokeOnMainThread( () =>
{
searchTerm = searchTerm.ToLower();
_ = SearchNewsDataAsync(searchTerm, UserConnected.NewsLanguage);
tasksearch = null;
});
});
}
}
catch (Exception ex)
{
}
}

Related

Multiple destination from xamarin forms

I have functional, which open google maps with route but with one point of destination. I want add several points of stop. How I can do it? See my code:
public Command OpenMap
{
get
{
return _openMap ?? (_openMap = new Command(async () =>
{
await Xamarin.Essentials.Map.OpenAsync(Position.Latitude, Position.Longitude, new MapLaunchOptions
{
Name = Address.Name,
NavigationMode = NavigationMode.Driving
});
}));
}
}
I use Xamarin.Essentials.Map maybe exists another way?
In the end, I want that after btn click have been open google maps with navigation route which consists of several destination.

How to conditionally PopAsync based on what page is currently show to user

Within the same page of my app the user can send off two websocket requests. That I then get two websocket responses. In each of those responses I pop the page from the nav stack. This is in their profile page where they can edit some basic info or change their password. Hopefully they usually would only do one but in the chance they do both and click save then it pops the page twice.
I have been trying to check the current page and if they are still on the profile page to go ahead and pop it but if they are not then skip the popping.
It seems like popasync is not actually removing the page from the stack because I will call the nav stack to a list afterwards to check and it's still there. I tried doing a check if any pages in the stack were the profile pages to then pop it. That still could be sloppy incase there were multiple instances of it in the stack but it would atleast get me in the right direction.
I also tried using MessagingCenter to bring it back to the code behind but that didn't do the trick either.
The main problem here is I only want to pop the page if that is the page the user is currently looking at.
If anyone could point me in the right direction that would be much appreciated.
else if (root.payload?.data?.updateUserFields != null)
{
DabGraphQlUpdateUserFields fields = root.payload.data.updateUserFields;
dbSettings.StoreSetting("Email", fields.email);
dbSettings.StoreSetting("FirstName", fields.firstName);
dbSettings.StoreSetting("LastName", fields.lastName);
GlobalResources.WaitStop();
var UserName = GlobalResources.GetUserName().Split(' ');
GuestStatus.Current.UserName = GlobalResources.GetUserName();
Device.BeginInvokeOnMainThread(() => { Application.Current.MainPage.DisplayAlert("Success", "User profile information has been updated", "OK"); ; });
DabProfileManagementPage profilePage = new DabProfileManagementPage();
Device.BeginInvokeOnMainThread(() =>
{
if (Application.Current.MainPage.Navigation.NavigationStack.Any(p => p is DabProfileManagementPage))
{
var existingPagess = Application.Current.MainPage.Navigation.NavigationStack.ToList();
Application.Current.MainPage.Navigation.PopAsync();
var _lastPage = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();
Application.Current.MainPage.Navigation.RemovePage(_lastPage);
var existingPages = Application.Current.MainPage.Navigation.NavigationStack.ToList();
}
});
//Device.BeginInvokeOnMainThread(() => { Application.Current.MainPage.Navigation.PopAsync(); });
}
else if (root.payload?.data?.updatePassword != null)
{
GlobalResources.WaitStop();
if (root.payload.data.updatePassword == true)
{
Device.BeginInvokeOnMainThread(() => { Application.Current.MainPage.DisplayAlert("Success", "Your password has been updated", "OK"); ; });
Device.BeginInvokeOnMainThread(() =>
{
if (Application.Current.MainPage.Navigation.NavigationStack.Any(p => p is DabProfileManagementPage))
{
var existingPagess = Application.Current.MainPage.Navigation.NavigationStack.ToList();
Application.Current.MainPage.Navigation.PopAsync();
var _lastPage = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();
Application.Current.MainPage.Navigation.RemovePage(_lastPage);
var existingPages = Application.Current.MainPage.Navigation.NavigationStack.ToList();
}
});
//Device.BeginInvokeOnMainThread(() => { Application.Current.MainPage.Navigation.PopAsync(); });
}
}
As Jason pointed out I just added variable of type int and increased it after a pop happened and reset it once it tries to go past 2. I also reset it to 0 once the user clicks to open the page again. The only issue, which shouldn't happen often is if the user tries to go and change info for a third time without leaving the page. No pop will happen. I thought about adding a timer but I have had apps get messy with timers before so I opted to keep it as is for now. Hoping I do find a way to pop once every time no matter how many times the user decides to hit that function.
else if (root.payload?.data?.updateUserFields != null)
{
DabGraphQlUpdateUserFields fields = root.payload.data.updateUserFields;
dbSettings.StoreSetting("Email", fields.email);
dbSettings.StoreSetting("FirstName", fields.firstName);
dbSettings.StoreSetting("LastName", fields.lastName);
GlobalResources.WaitStop();
var UserName = GlobalResources.GetUserName().Split(' ');
GuestStatus.Current.UserName = GlobalResources.GetUserName();
Device.BeginInvokeOnMainThread(() => { Application.Current.MainPage.DisplayAlert("Success", "User profile information has been updated", "OK"); ; });
if (popRequests < 1)
{
popRequests = popRequests + 1;
Device.BeginInvokeOnMainThread(() => { Application.Current.MainPage.Navigation.PopAsync(); });
}
else
popRequests = 0;
}
else if (root.payload?.data?.updatePassword != null)
{
GlobalResources.WaitStop();
if (root.payload.data.updatePassword == true)
{
Device.BeginInvokeOnMainThread(() => { Application.Current.MainPage.DisplayAlert("Success", "Your password has been updated", "OK"); ; });
if (popRequests < 2)
{
popRequests = popRequests + 1;
Device.BeginInvokeOnMainThread(() => { Application.Current.MainPage.Navigation.PopAsync(); });
}
else
popRequests = 1;
}
}

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);

in app purchase issue in windows store app

I have created an app with in app purchase and tested it with CurrentAppSimulator and works fine but when i create the package for app it fails
This is my code for which i am creating package
public async System.Threading.Tasks.Task InAppInit()
{
var listing = await CurrentApp.LoadListingInformationAsync();
// Delux Unlock - Durable
var unlockFeatureDelux = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "deluxe" && p.Value.ProductType == ProductType.Durable);
isDeluxPurchased = CurrentApp.LicenseInformation.ProductLicenses[unlockFeatureDelux.Value.ProductId].IsActive;
deluxProductID = unlockFeatureDelux.Value.ProductId;
// Standard Unlock - Durable
var unlockFeatureStandard = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "standard" && p.Value.ProductType == ProductType.Durable);
isStarndardPurchased = CurrentApp.LicenseInformation.ProductLicenses[unlockFeatureStandard.Value.ProductId].IsActive;
standardProductID = unlockFeatureStandard.Value.ProductId;
}
I am calling this method OnLaunched in App.xaml.cs
Based on our discussion here is what I would do:
The LoadListingInformationAsync method uses internet and if the user does not have an internet connection then it will throw an exception. So I suggest to wrap this whole stuff into a try/ctach block
As we see the ProductListings does not contain any item. I don't know how this list is populated, but as long as your app is not in the store I would not be surprised when that list is empty (Maybe someone can help out here... but i did not find anything regarding this in the docs). So for this I would just simply check if the feature you need is in the list... With this your package will pass the test you mentioned and you can upload it. If the list is also empty when the package is installed via the store, then something with the IAP setting is wrong (but that is related to the store..)
And a general comment: Obviously this code is not complete... You need some code for purchasing the IAPs and here we only get the Ids.. (But I think you only pasted the relevant part anyway.)
So all this in code:
public async System.Threading.Tasks.Task InAppInit()
{
try
{
var listing = await CurrentApp.LoadListingInformationAsync();
if (listing.ProductListings.ContainsKey("deluxe"))
{
// Delux Unlock - Durable
var unlockFeatureDelux = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "deluxe" && p.Value.ProductType == ProductType.Durable);
isDeluxPurchased = CurrentApp.LicenseInformation.ProductLicenses[unlockFeatureDelux.Value.ProductId].IsActive;
deluxProductID = unlockFeatureDelux.Value.ProductId;
}
else
{
//There is no deluxe IAP defined... so something with your IAP stuff is wrong...
}
if (listing.ProductListings.ContainsKey("standard"))
{
// Standard Unlock - Durable
var unlockFeatureStandard = listing.ProductListings.FirstOrDefault(p => p.Value.ProductId == "standard" && p.Value.ProductType == ProductType.Durable);
isStarndardPurchased = CurrentApp.LicenseInformation.ProductLicenses[unlockFeatureStandard.Value.ProductId].IsActive;
standardProductID = unlockFeatureStandard.Value.ProductId;
}
else
{
//same as for Delux
}
}
catch
{
//Show this on the UI...
}
}

Windows phone 8 and phonegap 2.7.0, Navigation between HTML pages and Xaml and back

I am developing an app, that will have a separate camera functionality. The reason is I do not like phonegap's builit in getPicture for windows phone as it automatically saves the image on the user's device, which will chew up alot of memory.
How my app currently works,
user opens app, app directs them to login.html page (where they enter username/pass) then to menu.html where they have a number of different options/features one of them is a take picture button, which opens camera.html in camera.html page i have this, code which calls my seperate Echo.cs class/plugin tool
cordova.exec(function (imageData) { onPhotoDataSuccess(imageData); }, function (err) {
alert("Intent Error. Unable to call update routines");
}, "Echo", "takePicture", ["takepicture"]);
my takePicture method looks like this:
public void takePicture(string options)
{
string takePic = null;
Debug.WriteLine("Reached imageconvert method");
try
{
string[] data = JsonHelper.Deserialize<string[]>(options);
takePic = data[0];
}
catch (Exception)
{
Debug.WriteLine("ERROR OCCURED!");
DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION));
return;
}
if ((takePic != null) && (takePic.Length > 0))
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
(Application.Current.RootVisual as PhoneApplicationFrame).Navigate(new Uri("/Camera.xaml", UriKind.Relative));
//logic here some way to get the image back from camera.xaml and resume my currant page.
});
//DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "imaged passed back from camera.xaml should go here"));
}
else
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Expected one non-empty string argument."));
return;
}
}
this code above, redirects the user to a seperate camera.xaml page I built where my custom camera processes an image without saving it to the user library and converts it to encoded 64basestring to send back as ImageData, My question now is, is there a way to send that ImageData information back some how and resume my app from Camera.html page? is this even possible with phonegap?
i have used to back:
DispatchCommandResult(new PluginResult(PluginResult.Status.OK, "imaged passed back from camera.xaml should go here"));
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
root = Application.Current.RootVisual as PhoneApplicationFrame;
root.GoBack();
});
if you use root.Navigate(new Uri("/MainPage.xaml", UriKind.Relative)); will lost the actual page and return to index
sorry my english

Categories