JavaFX button event triggers only once - events

So i have this JavaFX application, which contains a button, that is supposed to open the DirectoryChooser onclick. When i trigger it once, it does what it was supposed to do, perfectly fine. As soon as i close the DirectoryChooser Dialog, the button doesn't do anything anymore. I was searching the web for some "event resetting" or something similar, because i thought maybe the Event was still "active" and therefore doesn't trigger anymore, but without any results:
// first attempt
button.addEventFilter(MouseEvent.MOUSE_CLICKED,
new EventHandler<MouseEvent>() {
public void handle(MouseEvent e) {
// dirChooser.setTitle("Select Directory:");
file = dirChooser.showDialog(primaryStage);
// just incase only the DirectoryChooser wasn't opening
System.out.println("asdf");
// updates the application view with the new selected path
update();
// not sure, if this affects anything
// found it while looking for resetting of events
e.consume();
};
}
);
// secont attempt
button.setOnAction(new EventHandler<ActionEvent>() {
#Override public void handle(ActionEvent e) {
DirectoryChooser dirChooser = new DirectoryChooser();
dirChooser.setTitle("Select Directory:");
file = dirChooser.showDialog(primaryStage);
update();
}
});
Not sure if this is just a complete wrong approach, or if i'm missing something important there. I hope you guys can figure it out.

So after the help of Uluk Biy, i got the problem. In the update routine, the button is newly created and therefore it's event handler is not existent anymore. I added the button to the attributes so I don't need to replace it everytime when calling the update routine, and the event handler is still existent.

Related

Detect Back Arrow Press Of The NavigationPage in Xamarin Forms

Is there any way to detect the press of the back button of the Navigation Page in Xamarin forms?
You can override your navigation page "OnBackButtonPressed" method:
protected override bool OnBackButtonPressed()
{
Device.BeginInvokeOnMainThread(async () =>
{
if (await DisplayAlert("Exit?", "Are you sure you want to exit from this page?", "Yes", "No"))
{
base.OnBackButtonPressed();
await App.Navigation.PopAsync();
}
});
return true;
}
If you are using the shell, you can override the Shell's OnNavigating event:
void OnNavigating(object sender, ShellNavigatingEventArgs e)
{
// Cancel back navigation if data is unsaved
if (e.Source == ShellNavigationSource.Pop && !dataSaved)
{
e.Cancel();
}
}
Update:
OnBackButtonPressed event will get fired ONLY on Android when user press the Hardware back button.
Seems like you are more interested to implement when any page get disappeared you want to do something!
In that case:
You have the page's two methods -
protected override void OnAppearing()
{
base.OnAppearing();
Console.WriteLine("Hey, Im coming to your screen");
}
protected override void OnDisappearing()
{
base.OnDisappearing();
Console.WriteLine("Hey, Im going from your screen");
}
You can override those 2 methods on any page to track when they appear and disappear.
Recent updates to Xamarin forms mean you can now do this in an application made with Shell Navigation for navigation back arrow on both platforms.
Use the Shell.SetBackButtonBehavior method, for example running this code in the constructor of your page object will allow the back navigation to take place only when the bound viewmodel is not busy:
Shell.SetBackButtonBehavior(this, new BackButtonBehavior
{
Command = new Command(async() =>
{
if (ViewModel.IsNotBusy)
{
await Shell.Current.Navigation.PopAsync();
}
})
});
In the body of the Command you can do whatever you need to do when you are intercepting the click of the back button.
Note that this will affect only the navigation back button, not the Android hardware back button - that will need handling separately as per the answers above. You could write a shared method called from both the back button pressed override and the command on shell back button behaviour places to share the logic.
You must override native navigationbar button behavior with custom renderer. OnBackButtonPressed triggers only physical device button. You can read good article how to achive this here

New UI Button misunderstood pointer click and pointer down action

I am making a game with ui controller. i use button to make that controller.
in the picture, i have "A" button. when my "character" facing npc, i want to talk with that npc with click that button. when dialogue is over, i need to close the dialogue box using this button too.
but what i got is, this button clicked over and over, so the first dialogue is skipped, and the dialogue which is showed up is the third or maybe the fourth dialog.
i attach event trigger on this button.
and this is my code that is attached on that event trigger
using UnityEngine;
using System.Collections;
public class aButtonScript : MonoBehaviour {
void Start(){
}
public void click(){
if(walkingScript.walking.interact == true)
{
loadGame.loadSave.objPrince.GetComponent<plantingScript>().aButton = false;
loadGame.loadSave.objPrince.GetComponent<walkingScript>().aButton = true;
}
}
public void clicked()
{
if(plantingScript.planting.toolBoxCanvas != null)
{
loadGame.loadSave.objPrince.GetComponent<plantingScript>().aButton = false;
choosingTools.ct.setTool();
}
}
public void unclicked()
{
loadGame.loadSave.objPrince.GetComponent<plantingScript>().aButton = false;
}
}
well, this is my first time making a game. hope whoever who read this question can help me. sorry for my bad english. thank you.
Not quite sure, but I've had similar problems when using GetMouseButton instead of GetMouseButtonDown. The first one triggers for each frame the button is pressed. Looking at your UI setup it seems you acivate the script when the button is pressed, for each frame it is pressed, and finally when it is released.

How to handle OnBackKeyPress correctly?

To make it simple, I create a new app, which contains MainPage, and Page2.
MainPage has a button, which navigates to Page2. Also override MainPage.OnBackKeyPress:
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
if (MessageBox.Show("Quit?", "Confirm", MessageBoxButton.OKCancel) == MessageBoxResult.Cancel)
e.Cancel = true;
else
base.OnBackKeyPress(e);
}
Page2 is empty, except override OnNavigateFrom, to simulate a long time operation when back from Page2 to MainPage:
protected override void OnNavigatedFrom(NavigationEventArgs e)
{
System.Threading.Thread.Sleep(1000);
base.OnNavigatedFrom(e);
}
Everything is ok, but when I am at Page2, and press Back key 3-4 times very quickly, then I see the message box popup twice.
I expect the message box not shown, or at least show and hide. Is there anything wrong in my code? Thanks.
It depends on what you mean by very quickly...
The code looks OK (apart from the Thread.Sleep which is presumably to simulate a long operation on the UI thread).
I expect this is because while the UI thread is busy (or "sleeping") the back key presses are still registering and being sent to the app, and when the UI thread is available again it will process them one after the other.
This is a good example of why you should avoid blocking the UI thread.

Do code after OnNavigatedTo

I Have Code get IdUsers From Other Page
String IdUsers;
public Main_Wallets_Page()
{
InitializeComponent();
MessageBox.Show(IdUsers);
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
String Id;
if (NavigationContext.QueryString.TryGetValue("IdUsers", out Id))
IdUsers = Id;
}
The MessageBox Alway be Null. I Want to MessageBox Show the "IdUsers" after OnNavigationTo (Do not put the MessageBox IN "OnNavigationTo").
How can i do it ?
You shouldn't use MessageBoxes in OnNavigatedTo because if the user does not press a button your app will crash since the framework thinks that navigation has failed. MessageBoxes in the constructor are equally as bad.
I can think of two options (I use #1 for these sorts of things):
Show the MessageBox in the Loaded event. But be careful it can be
fired more than once. In the constructor you might add the handler for the Loaded event and then in the handler you'd detach from the handler so that it is called only once.
Use Dispatcher.BeginInvoke around the MessageBox.Show call so that it does not block navigation. That might still block the Dispatcher thread. If you really wanted to go this route you could use ThreadPool.QueueUserWorkItem or a TPL Task.
I also have used OnLayoutUpdated in place of the Loaded event but I can't remember exactly why :) It seems like it might have been that the page hasn't yet displayed in Loaded and it has in the other event.
If this value was initialized, you can store it in application isolated storage. Then, when constructor is called, you can read it from there. In this case value of user ID will be initialized and MessageBox won't show you NULL.
DO NOT place MessageBox into OnNavigatedTo event.
Try to create an empty project with MainPage and Page2. Place button on MainPage to navigate to Page2. In Page2 place MessageBox in OnNavigatedTo event. Then everythig will work fine if you Start Debugging from VS. BUT if you deploy and run it you will see that when you navigate to Page2 you see MessageBox. Then don't do anything, just wait for about 15 sec. MessageBox will react as Canceled and APPLICATION WILL BE CRASHED! without any navigation to Page2 or MainPage. The same thing happens if you use Dispatcher.BeginInvoke around the MessageBox.Show.
I assume that OnNavigatedTo event has a timeout which works only when app is deployed. So you should run your MessageBox when Navigation is competed.
Everything works if you do
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) {
base.OnNavigatedTo(e);
var lcTimer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 0, 0, 200) };
lcTimer.Tick += (s2, e2) => {
(s2 as DispatcherTimer).Stop();
if (MessageBoxResult.OK == MessageBox.Show("Test, don't push", "", MessageBoxButton.OKCancel))
MessageBox.Show("OK");
else
MessageBox.Show("Cancel");
};
lcTimer.Start();
}
Note: If you have some code in OnNavigatedTo run above code at the end of OnNavigatedTo.
I liked what Austin Thompson(upvote) has adviced with ThreadPool.QueueUserWorkItem. But note that with this approach you need to place MessageBox inside the Dispatcher.BeginInvoke otherwise you will receive cross-thread exception. So the code is the following
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e) {
base.OnNavigatedTo(e);
ThreadPool.QueueUserWorkItem((stateInfo) => {
Dispatcher.BeginInvoke(() => {
if (MessageBoxResult.OK == MessageBox.Show("Test don't push", "", MessageBoxButton.OKCancel))
MessageBox.Show("OK");
else
MessageBox.Show("Cancel");
});
});
}

Is it possible to preload an assembly in Windows Phone 7?

I have an app in which I have a lot of references and the load time was not acceptable to me. I have removed the splash screen image and created an animated loading screen by having a separate project with no reference to the main application which then navigates to the first page of the rest of the app. It does start up fast now but it's a little lacking still.
I would like to do another animation right before the load screen goes away. The only way I can think of to do this is to actually preload the assemblies needed for the navigation to the next page, do an animation, and then navigate.
I have tried
OnNavigatedFrom but the animation doesn't have time to run since the page will be replaced by the new page very quickly from that point.
OnNavigatingFrom is no help either as it is called as soon as I call NavigationService.Navigate();
Searching the web and Stack Overflow :)
I also considered faking it a bit by having the next page show a duplicate of the load screen and do the last animation there, but it can't match the current state of the load screen animation and is harder to maintain
Thanks for any ideas!
If you want to force the loading of an assembly, just reference a type from this assembly.
For instance, something like Console.WriteLine(typeof(YourAssembly.SomeType)); will force the loading of YourAssembly.
Now for your problem, maybe you can use usercontrols? Put the content of your main page in a user control. Display the loading page, create the usercontrol in the background, let the animation play, then when the animation is done playing replace the page's content with the usercontrol.
It turns out that you can preload by just creating a new instance of the page you are going to navigate to. Unfortunately that has to be done on the UI thread which can cause animation slowdown, at least in my experience.
Here is a sample of how to do an animation, then preload, then do another animation before navigating. :
public partial class LoadScreen : PhoneApplicationPage
{
public LoadScreen()
{
InitializeComponent();
this.Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
var sb = new Storyboard();
// create your animation here
sb.Completed += (sender, args) => PreLoad();
sb.Begin();
}
private void PreLoad()
{
// this is the part that actually takes time and causes things to get loaded
// you may need it in a try/catch block depending on what is in your constructor
var page = new PageToNavigateTo();
// now create an animation at the end of which we navigate away
var sbOut = new Storyboard();
// create your animation here
sbOut.Completed += (sender, args) => NavigateToNextScreen();
sbOut.Begin();
}
private void NavigateToNextScreen()
{
// navigate here
}
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
// remove the loading screen from the backstack so the user doesn't see it again when hitting the back button
NavigationService.RemoveBackEntry();
}
}

Resources