Trigger QuerySubmitted once - c#

I have a AutoSuggestBox with QuerySubmitted property, so when I hit enter button , it will search for products and will show error message when no data found , my problem is it will show twice or multiple times when i hit enter multiple times too.
here is my code:
try {
if (!ViewModel.IsBusy) {
ViewModel.IsBusy = true;
await this.ViewModel.FindAsync(args.QueryText);
}
}
catch (Exception e) {
}
finally {
ViewModel.IsBusy = false;
}

Its because the second call to your function is making the bool false and hence the 3rd call will go into if condition and will do a FindAsync()
Instead you can do this :
try {
if (!ViewModel.IsBusy) {
ViewModel.IsBusy = true;
await this.ViewModel.FindAsync(args.QueryText);
ViewModel.IsBusy = false;
}
}
catch (Exception e) {
ViewModel.IsBusy = false;
}
Or you can really use Task Cancellation for better design and you will get the benefit of sending the latest args.QueryText to the FindAsync if there are changes in querytext between multiple Enter key hit. Of course, you need to cancel the earlier Task if you encounter that there is a new call.

Related

Cannot modify the document for either a read-only external command is being executed, or changes to the document are temporarily disabled

I want to set parameter values of the elements when the DocumentChanged event is triggered. I know that the event is read-only.
Is there any another way (except IUpdater) to do it? Except IUpdater because I want every changes in the document.
Here is my code
public Result OnStartup(UIControlledApplication application)
{
try
{
// Event handler for document changing
application.ControlledApplication.DocumentChanged += new EventHandler<DocumentChangedEventArgs>(Application_DocumentChanged);
}
catch (Exception)
{
return Result.Failed;
}
return Result.Succeeded;
}
private void Application_DocumentChanged(object sender, DocumentChangedEventArgs e)
{
Document doc = e.GetDocument();
// Record added elements
if (e.GetAddedElementIds().Count() > 0)
{
using (Transaction transaction = new Transaction(doc))
{
try
{
transaction.Start("Set TCP Parameters");
foreach(ElementId el_id in e.GetAddedElementIds())
{
doc.GetElement(element_id).get_Parameter(new Guid("6558f207-e777-0758-2023-2f34e722cb01")).Set(200)
}
}
catch (Exception ex)
{
TaskDialog.Show("Error: Transaction", ex.Message);
}
transaction.Commit();
}
}
TaskDialog.Show("Document Changed", e.Operation.ToString());
}
I will really appreciate any ideas
You ask: Is there any another way?
Yes. You can subscribe to a one-off shot of the Idling event, cf. Reacting to Changes and Setting Parameters using DMU or DocumentChanged
This has been discussed repeatedly by The Building Coder and in the Revit API discussion forum. Some related articles are listed in the topic group on Idling and External Events for Modeless Access and Driving Revit from Outside.

How suppress multiple button clicks?

I would like to know the best way to handle an http Request on Xamarin.Forms.
For now I was handling the request this way:
First I have a button on my forms like this:
btn_1.Clicked += (sender, e) => {
Confirm(name, password);
};
My Confirm() function checks the entrees and throws the event of the request. Also it do the logic after the request event is completed. For example:
private async void Confirm(string name, string password) {
UserController user_controller = new UserController();
if (name != null && password != null) {
User user = new User(name, password);
bool ok = user_controller.Login(user);
if(ok){
Navigation.InsertPageBefore(new NextPage(), this);
await Navigation.PopAsync();
} else {
//Show error code...
}
}
}
My UserController has two functions for each http request. The first one does the request. The second one calls the first one and handles the answer.
1º:
private async Task<HttpResponseMessage> user_login(User user){
try {
Uri uri = new Uri("http://localhost/user/login");
string user_json = JsonConvert.SerializeObject(user);
StringContent content = new StringContent(user_json, Encoding.UTF8, "application/json");
return await Utilities.client.PostAsync(uri, content).ConfigureAwait(false);
} catch {
return null;
}
}
2º:
public bool Login(User user) {
http_response = user_login(user).GetAwaiter().GetResult();
//If it doesn't reach the server...
if (http_response != null) {
//Depending of the status of the response
switch (http_response.StatusCode) {
case (System.Net.HttpStatusCode)200:
try {
string content = http_response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Response response = JsonConvert.DeserializeObject<Response>(content);
return (bool) response.aux;
} catch {
}
break;
case (System.Net.HttpStatusCode)401:
...
break;
default:
...
break;
}
} else {
App.Current.MainPage.DisplayAlert("Error", "No server connection", "OK");
}
return false;
}
This completes my protocol for each request. My problem is:
1. I'm not sure if this is the correct way to do it
2. When I click several times the btn_1 it throws many times the request
How could I do to avoid this? I try to put a lock on my button but it doesn't work. I'm having many troubles with the asynchronous requests. I don't know which is the best way to handle the request to throw only one request at the time.
EDIT:
I have created this button extension:
public partial class LockableButton: Button {
public event EventHandler ThrowEvent;
public bool ShowLoading { get; set; }
public LockableSimpleButton() {
ShowLoading=false;
InitializeComponent();
this.Clicked += async (object sender,EventArgs e) => {
if (!Utilities.Unlocked) { return; }
Utilities.Unlocked=false;
try {
if (ShowLoading) {
await Navigation.PushModalAsync(new LoadingPopUp());
ThrowEvent(sender,e);
await Navigation.PopModalAsync();
} else {
ThrowEvent(sender,e);
}
} finally {
await Task.Delay(1000);
Utilities.Unlocked=true;
}
};
}
}
And now my buttons are like this:
btn_1.ThrowEvent += async (sender, e) => {
Navigation.InsertPageBefore(new Page(),this);
await Navigation.PopAsync(false);
};
How it is even posible that the error still persisting?
When I click several times the button it throws an error because it is trying to PopAsyc to many time the same page... It is the delay to short?
When I click several times the btn_1 it throws many times the request
This problem has nothing to do with handling an Async HTTP Request.
Here are two classic coding techniques for discarding extra button presses.
They are variations on having a flag set, and discarding any clicks that happen while that flag is set.
Common pseudo-code:
static bool _busy;
...click handler... {
if (_busy) return;
_busy = true;
// Special code as needed.
... handle the click ...
// This code must always be executed.
// If it isn't, the button action will never occur again.
_busy = false;
}
When you finish processing the first click, start a one-time timer. Until that timer fires, discard any additional clicks.
Pseudo-code:
...click handler... {
if (_busy) return;
_busy = true;
try {
... handle the click ...
} finally {
var timer = new Timer(TimerTick, 250 milliseconds, one-time);
timer.Start();
}
}
void TimerTick() {
// This code must always be executed.
// If it isn't, the button action will never occur again.
_busy = false;
//maybe timer.Stop();
}
When you start processing the first click, set a flag. Clear that flag when you are done processing. Discard any clicks that happen while that flag is set.
Pseudo-code:
// Must be `async` method, so events continue while processing.
// Otherwise, the second button press might simply be on hold,
// until after this finishes, so doesn't get suppressed.
...click handler... {
if (_busy) return;
_busy = true;
try {
... handle the click ...
} finally {
// This code must always be executed.
// If it isn't, the button action will never occur again.
_busy = false;
}
}

C# WINFORMS - Making a button display a string variable from a class instantiation

I am making a basic text-based fighting game. I have a class called move. My class has a string variable called DisplayName. I have this code:
try
{
m1.Text = playerMoves[0].displayName;
}
catch (Exception)
{
m1.Visible = false;
}
try
{
m2.Text = playerMoves[1].displayName;
}
catch (Exception)
{
m2.Visible = false;
}
try
{
m3.Text = playerMoves[2].displayName;
}
catch (Exception)
{
m3.Visible = false;
}
try
{
m4.Text = playerMoves[3].displayName;
}
catch (Exception)
{
m4.Visible = false;
}
try
{
m5.Text = playerMoves[4].displayName;
}
catch (Exception)
{
m5.Visible = false;
}
try
{
m6.Text = playerMoves[5].displayName;
}
catch (Exception)
{
m6.Visible = false;
}
This code is in a button click-event that starts the battle. m1, m2, m3, m4, m5, and m6 are all buttons. They are all in a hidden panel that gets displayed before the code above is ran.
So, I have a List collection that holds instantiations of the class move. In my Form1_Load event, I load the user's moves from an XML File. I also have a class called user. It has the user's level and other stuff in it. Whenever you win a fight, you will earn a move depending on your level. It adds it to the playerMoves collection.
But for some reason, it only displays the first button. If I walk through my code, it doesn't go into the catch, but it makes the second button (I am testing it with the second button) gets the DisplayName from playerMoves[1], but when my form comes back up after I finish walking through the code, it only displays the first button.
I have made sure that all the buttons are already visible before I run the code above, so can anyone explain to me what is wrong with my code? I am comepletely lost.
I don't think so that it is good approach to use try & catch. you can use if else condition like below. and considering all buttons are set visible to false by default.
if(!String.IsNullOrEmpty(Convert.ToString(playerMoves[0].displayName)))
{
m1.Text = playerMoves[0].displayName;
m1.Visible=true;
}
else
{
m1.Visible=true;
}

List box selection with time consuming task that needs to update the UI

I have an application that performs a time consuming task when the user selects an item for a listbox.
When a user selects a show the application will retrieve all the shows information form the tvdb and the display it in the Ui.
The problem occurs when a user quickly changes selection while the show is still loading.
I would like to make it so that a user could change their mind and then make another selection while the first was loading and have that information displayed in the Ui.
I have created a simple demonstration application to show the problem : Demo App .
This is what i tried to do
List box selection event handler
private void lb1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string sid = lb1.SelectedItem.ToString();
try
{
LoadSeries(Int32.Parse(sid));
}
catch (FormatException)
{
MessageBox.Show("Please enter a valid series id");
}
}
LoadSeries
private void LoadSeries(int _seriesId)
{
Task<TvdbSeries> series = Task.Factory.StartNew(() =>
{
TvdbSeries seriesloaded = null;
try
{
seriesloaded = m_tvdbHandler.GetSeries(_seriesId, TvdbLanguage.DefaultLanguage, true, true, true, true);
}
catch (TvdbInvalidApiKeyException ex)
{
MessageBox.Show(ex.Message);
}
catch (TvdbNotAvailableException ex)
{
MessageBox.Show(ex.Message);
}
return seriesloaded;
}
);
series.ContinueWith((antecedent) =>
{
UpdateSeries(series.Result);
},
TaskScheduler.FromCurrentSynchronizationContext()
);
}
If a user changes selection quickly the application errors on the line seriesloaded = m_tvdbHandler.GetSeries(_seriesId, TvdbLanguage.DefaultLanguage, true, true, true, true); and shows this message in the debugger "WebClient does not support concurrent I/O operations."
I did find out that it is because I am making a new request before the last one is finished but I have no way of chaining the code in m_tvdbHandler.GetSeries because its functionality comes from library i am using and some one else wrote .
This is the library tvdblib , I am sure the problem is with how I am doing things and not the library .
when a user makes a selection you can disable the UI till the information is loaded completely and display a message at the bottom loading please wait. Once everything is loaded, enable the Ui and hide the message.
You are posting this question as a C#5.0 question, so you should be using async/await as much as you can.
private Task<TvdbSeries> LoadSeriesAsync(int _seriesId)
{
return Task.Run(() =>
{
TvdbSeries seriesloaded = null;
try
{
seriesloaded = m_tvdbHandler.GetSeries(_seriesId, TvdbLanguage.DefaultLanguage, true, true, true, true);
}
catch (TvdbInvalidApiKeyException ex)
{
MessageBox.Show(ex.Message);
}
catch (TvdbNotAvailableException ex)
{
MessageBox.Show(ex.Message);
}
return seriesloaded;
}
);
}
It would be much better if there was a LoadSeriesAsync.
One way to do it would be to disable lb1 while retrieving the series.
private async void lb1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
string sid = lb1.SelectedItem.ToString();
try
{
lb1.IsEnabled = false;
var series = await LoadSeriesAsync(Int32.Parse(sid));
UpdateSeries(series);
}
catch (FormatException)
{
MessageBox.Show("Please enter a valid series id");
lb1.IsEnabled = true;
}
}

Back Button/ Cancel Button during In App Purchase

I am having trouble detecting the Exception that is thrown by the in-app-purchase store during Unit Test (Beta app) for Windows Phone 8 when I press the Cancel or Back button on the phone. The app simply exits.
There are no errors when I use the MockIAP. Cancel or Back Button returns an empty receipt variable during the await receipt = Store... It is handled correctly in MockIAP. But apparently Unit Test and the real app Store handleds Cancel or Back events differently. The app simply exits, which I believe because it is throwing an unhandled error.
My app is a Phonegap 2.3 and the purchase part is handled by the plugin. Unlike the MockIAP, I can't see (i.e. attach break points) what is happening on the wrapper side when Cancel or Back button is pressed during purchase. I have tried showing MessageBox.Show for every step of the purchase. The MessageBox.Show code is working when I press confirm purchase but not when I press Cancel or Back Button. I have made it synchronous already with EventWaitHandle.
In addition, I have set e.Handled = true for the unhandled Exception event to try to stop it from exit the app with no luck.
From online, my purchase code is boilerplate, so I dont' understand why other people hasn't come across this problem before, and why there are no solutions online. Does anyone have any idea how to fix this?
Purchase.cs (Plugin):
private static string receipt;
private async void purchaseProduct()
{
bool canBuy = false;
try
{
li = await Store.CurrentApp.LoadListingInformationAsync();
if (li.ProductListings.ContainsKey(package_id))
{
canBuy = true;
EventWaitHandle Wait = new AutoResetEvent(false);
Deployment.Current.Dispatcher.BeginInvoke(async () =>
{
// Here is the problem.. Don't know what is passed back to receipt when Cancel or Back is pressed, which is causing the app to close during Unit Test but not MockIAP
receipt = await Store.CurrentApp.RequestProductPurchaseAsync(package_id, true);
receipt = receipt.ToString();
Wait.Set();
});
Wait.WaitOne();
}
}
catch(Exception e)
{
var eMsg = e.Message.ToString();
errorMsg("Catch Exception: ", eMsg);
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
}
finally
{
errorMsg("Receipt with await: ", receipt);
if (canBuy && receipt!= "")
{
errorMsg("Hitting the parsing", "");
parseXML(receipt);
prepData();
httpPostData();
Store.CurrentApp.ReportProductFulfillment(package_id);
}
else
{
errorMsg("Else Finally", "");
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
}
}
}
private static void errorMsg(String caption, String msg)
{
EventWaitHandle Wait = new AutoResetEvent(false);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(caption + msg);
Wait.Set();
});
Wait.WaitOne();
}
App.cs
private void Application_UnhandledException(object sender, ApplicationUnhandledExceptionEventArgs e)
{
Exception ex = (Exception)e.ExceptionObject;
EventWaitHandle Wait = new AutoResetEvent(false);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
MessageBox.Show("Unhandled Exception: " + ex.Message);
Wait.Set();
});
Wait.WaitOne();
// Stop from exiting..
e.Handled = true;
if (System.Diagnostics.Debugger.IsAttached)
{
// An unhandled exception has occurred; break into the debugger
//System.Diagnostics.Debugger.Break();
}
}
to fix this enclose try/catch around RequestProductPurchaseAsync method call even though you had a try/catch for entire method...
try
{
receipt = await CurrentApp.RequestProductPurchaseAsync("MyItem", false);
}
catch (Exception){}
.... other code

Categories

Resources