So I have a button on a WinRT UserControl that I want to increase or decrease a integer value (CurrentValue) while you hold down the button.
I ended up with this implementation below, which works but does not look to good or is it okay?
I searched for an event to use but I got stuck using click and setting the button.clickmode to press.
I use the bool _increasePushed to track if already pushed in so I don't get multiple event triggers.
private bool _increasePushed;
private const int PushDelay = 200;
private async void ButtonIncreaseClick(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (button == null) return;
if (_increasePushed)
{
return;
}
_increasePushed = true;
while (button.IsPressed)
{
CurrentValue++;
await Task.Delay(PushDelay);
}
_increasePushed = false;
}
XAML on UserControl
<Button x:Name="buttonIncrease" Content="Bla bla"
Click="ButtonIncreaseClick" ClickMode="Press" />
The better way would be to use a RepeatButton which does exactly what you are trying to replicate. It has a Delay property to wait for the first repeated click as well as an Interval property that controls how often the Click event is raised.
Related
I'm struggling with the WebBrowser control (both in Winforms and WPF). Basically I want to achieve the same behavior I got with a RTF editor: Handling some kind of OnTextInput event in order to get the last typed character for every keystroke.
I mean the textual characters, not Control, Alt, F5, Enter, ... that can be captured with the Keydown/Keyup events.
Any help? Thanks in advance.
You can hanlde KeyPress event of this.webBrowser1.Document.Body:
private void Form1_Load(object sender, EventArgs e)
{
this.webBrowser1.Navigate("http://www.google.com");
//Attach a handler to DocumentCompleted
this.webBrowser1.DocumentCompleted += webBrowser1_DocumentCompleted;
}
void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
//Attach a handler to Body.KeyPress when the document completed
this.webBrowser1.Document.Body.KeyPress += Body_KeyPress;
}
void Body_KeyPress(object sender, HtmlElementEventArgs e)
{
//handle the event, for example show a message box
MessageBox.Show(((char)e.KeyPressedCode).ToString());
}
Note:
It doesn't handle non-input keys as you need.
You can also suppress the input by setting e.ReturnValue = false; based on some criteria if you need.
You can also handle other key events like KeyUp and KeyDown the same way
So once again we are in the process of converting our existing Java application that was using entirely Swing to using JavaFX. However, the application will not be using JavaFX entirely. This seems to be causing some issues with Alerts/Dialogs and modality. We are currently using Java 8u40.
The main application is basically in a JFrame that has a Menu. The main content pane is JDesktopPane and clicking a MenuItem opens new JInternalFrames within the DeskopPane. Screens we are converting to JavaFX are basically JFXPanels within a JInternalFrame at the moment. Any Alerts/Dialogs that are opened from the JFXPanels are modal to the panel itself, but not to the JInternalFrame, DeskopPane, Menu, etc.
I read in the DialogPane documentation that they are planning to introduce some lightweight dialogs and even possibly InternalFrames in future releases of JavaFX, so maybe we'll just have to wait it out a little longer for this functionality. But, ideally when opening a new Alert/Dialog it would be modal to the entire Application.
EDIT:
Currently doing the following for modal dialogs:
((Stage)getDialogPane().getScene().getWindow()).setAlwaysOnTop(true);
This makes the dialog always appear on top, however the dialog also remains on top of other applications even if our main application is minimized. It also does not block input to any Swing components in the frame.
You can use the following work-around which creates an invisible JDialog when the Alert is shown and disposes the JDialog when the Alert is closed. This approach extends the modality to the whole application, including the Swing part.
// create Alert
Alert alert = new Alert(AlertType.INFORMATION, "Hello");
// create invisible JDialog and "show" it
JDialog dialog = new JDialog();
dialog.setModal(true);
dialog.setUndecorated(true);
dialog.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
SwingUtilities.invokeLater(() -> dialog.setVisible(true));
// show Alert
alert.showAndWait();
// close JDialog after Alert is closed
dialog.dispose();
I don't think i understand your question completely. But here is my guess - You are trying to make an alert window from some JFXPanel that will be modal (i.e. user will not be able to click in your application until she closes that alert window) to your entire application which is written partially using swing components.
If your application would be written in purely JavaFX then you would do something like (Assuming you have created a button somewhere in your JFXPanel)
button.setOnAction(evt -> {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.initModality(Modality.APPLICATION_MODAL);
// This will not work in your code
alert.initOwner(button.getScene().getWindow());
alert.show();
});
but since initOwner requires a javafx.stage.window object passing a swing component won't work in your code. As of Java 8u40 i don't think there is a right way(i.e. not hacks) to set ownership of Alert objects to swing component. Not surprisingly such questions has already been asked here and not answered as of writing this.
For your requirements you can use JOptionPane.showMessageDialog method and its look alike as workaround.
button.setOnAction(evt -> {
JOptionPane.showMessageDialog(desktopPane,"My message");
});
These dialog boxes are modal by default so no work is necessary. You can call these from any event handler methods of JavaFX components.
I've done a little workaround with a small interface which is implemented in my JavaFXFrame:
public interface DialogParent {
void setOnFocusGained(EventHandler<FocusEvent> focusHandler);
void setOnCloseRequest(EventHandler<WindowEvent> closeHandler);
}
And my JavaFXFrame implementation
public class JavaFXFrame implements DialogParent {
private JFrame frame;
private EventHandler<ch.irix.sumadmin.util.FocusEvent> focusGainedHandler;
private EventHandler<javafx.stage.WindowEvent> windowClosingHandler;
public void JavaFXFrame() {
final JFXPanel fxPanel = new JFXPanel();
frame = new JFrame();
frame.add(fxPanel);
frame.addWindowListener(new WindowAdapter() {
#Override
public void windowClosing(WindowEvent e) {
tryClosing(this);
}
});
frame.addWindowFocusListener(new WindowAdapter() {
#Override
public void windowGainedFocus(WindowEvent e) {
if (focusGainedHandler != null) {
focusGainedHandler.handle(new FocusEvent());
}
}
});
}
public void setVisible(boolean visible) {
frame.setVisible(visible);
}
private void tryClosing(WindowListener listener) {
javafx.stage.WindowEvent windowEvent = new javafx.stage.WindowEvent(null, javafx.stage.WindowEvent.WINDOW_CLOSE_REQUEST);
if (windowClosingHandler != null) {
windowClosingHandler.handle(windowEvent);
}
if (!windowEvent.isConsumed()) {
frame.setVisible(false);
}
}
#Override
public void setOnFocusGained(EventHandler<ch.irix.sumadmin.util.FocusEvent> focusGainedHandler) {
this.focusGainedHandler = focusGainedHandler;
}
#Override
public void setOnCloseRequest(EventHandler<javafx.stage.WindowEvent> windowClosingHandler) {
this.windowClosingHandler = windowClosingHandler;
}
}
And showing an Alert:
public static void showAlert(Alert alert) {
DialogPane dialogPane = alert.getDialogPane();
final Stage stage = new Stage();
stage.setScene(dialogPane.getScene());
List<ButtonType> buttonTypes = dialogPane.getButtonTypes();
for (ButtonType buttonType : buttonTypes) {
ButtonBase button = (ButtonBase) dialogPane.lookupButton(buttonType);
button.setOnAction(evt -> {
dialogPane.setUserData(buttonType);
stage.close();
});
}
dialogParent.setOnFocusGained(event -> {
stage.toFront();
});
dialogParent.setOnCloseRequest(Event::consume);
stage.setOnCloseRequest(event -> {
dialogParent.setOnFocusGained(null);
dialogParent.setOnCloseRequest(null);
});
stage.show();
}
Hope this will help you
As described i input a datepicker in my xaml file
when i run the page ,datepicker just show like this:
then I have to tap the datepicker to enter the select page like this :
Now
I need to directly open the fullscreen datepicker select page when I click a button
the address give a way that I can just Navigate to the select page,
but I don't know how ?
I'm the poster.
i find a solution myself
Override DatePicker class with our custom DatePickerCustom class. Create new class "DatePickerCustom.cs"
public class DatePickerCustom : DatePicker
{
public void ClickTemplateButton()
{
Button btn = (GetTemplateChild("DateTimeButton") as Button);
ButtonAutomationPeer peer = new ButtonAutomationPeer(btn);
IInvokeProvider provider = (peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider);
provider.Invoke();
}
}
then in the mainpage.xaml.cs
private DatePickerCustom datePicker;
// Constructor
public MainPage()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MainPage_Loaded);
}
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
// create datePicker programmatically
if (this.datePicker == null)
{
this.datePicker = new DatePickerCustom();
this.datePicker.IsTabStop = false;
this.datePicker.MaxHeight = 0;
this.datePicker.ValueChanged += new EventHandler<DateTimeValueChangedEventArgs>(datePicker_ValueChanged);
LayoutRoot.Children.Add(this.datePicker);
}
}
void datePicker_ValueChanged(object sender, DateTimeValueChangedEventArgs e)
{
// now we may use got value from datePicker
TextBlock1.Text = this.datePicker.ValueString;
}
so that when do an action like tap or click, the fullscreen datepicker page will be shown
private void button1_Click(object sender, RoutedEventArgs e)
{
this.datePicker.ClickTemplateButton();
}
ps: timepicker can also do the same thing
ps2:here is the details
#Mario Galván
hope it help u
I am working on a Windows Phone 8 App which should be protected with a passcode. What is the best way to show the passcode screen everytime the app is lauchend or activated?
I think the central point of action shoule be the App.xaml.cs with its Launch and Activation event handlers. But how exactly can I show the passcode screen?
The problem is, that one never know which pages will be displayed when the app launches or is reactivated. It is either the main page or any other page which was last displayed when the app was deactivated.
I tried to intercept the navigation to the first page, cancel it and show the passcode page instead:
// App.xaml.cs
private void InitializePhoneApplication() {
...
RootFrame.Navigating += HandleFirstNavigation;
...
}
private void HandleFirstNavigation(object sender, NavigatingCancelEventArgs e) {
RootFrame.Navigating -= HandleFirstNavigation;
e.Cancel = true;
RootFrame.Dispatcher.BeginInvoke(new Action(this.OpenPasscodePage));
}
private void OpenPasscodePage() {
RootFrame.Navigate(PasscodePageUri);
}
This works, but only when the app lauchend. When the app reactivated (dormant or tombstoned) the e.Cancel is irgnored. Although the navigation to the passcode page is called the original page is shown.
Moving the navigation the the passcode page from Navigating to Navigated does not worth either:
private void InitializePhoneApplication() {
...
RootFrame.Navigated += PasscodePageAfterFirstNavigation;
...
}
private void PasscodePageAfterFirstNavigation(object sender, EventArgs e) {
RootFrame.Navigated-= PasscodePageAfterFirstNavigation;
RootFrame.Navigate(PasscodePageUri);
}
This seems to be some kind of race condition: Sometimes the passcode page is shown, sometimes the original page. Even if the passcode pages comes up this looks bad because one first see the original page for the fraction of a second before the app navigates further to the passcode page.
Both solution do not work. Any idea what is the right way to implement this?
EDIT: Meanwhile I tried a third solution which does not work either. This solution uses the Uri Mapper:
App.xaml.cs
public bool PasscodeWasConfirmed; private void Application_Launching(object sender, LaunchingEventArgs e) {
...
PasscodeWasConfirmed = false;
...
}
private void Application_Activated(object sender, ActivatedEventArgs e) {
...
PasscodeWasConfirmed = false;
...
}
public Uri InitialPageUri;
public bool ShouldRedirectToPasscodePage(Uri uri) {
if (PasswordWasConfirmend == false) {
InitialPageUri = uri;
return true;
}
return false;
}
UriMapper
public class AppUriMapper : UriMapperBase {
public override Uri MapUri(Uri uri) {
App app = (Application.Current as App);
if (app != null) {
if (app.ShouldRedirectToPasscodePage(uri))
return PasscodeQueryPage.PageUri;
}
// default
return uri;
}
}
PasscodePage
public partial class PasscodePage : PhoneApplicationPage {
...
private void PasscodeConfirmed() {
App app = (Application.Current as App);
app.PasscodeWasConfirmed = true;
NavigationService.Navigate(app.InitialPageUri);
}
}
The Logic is working without any problem, but the app does not navigate to InitialPageUri after the passcode was confirmed. The Uri Mapper is called and correctly and returns the InitialPageUri (no redirect any more). But no navigation happens...
There are no errors, exceptions or debug output. simply nothing happes...
Biggest problem when using Uri Mapper:
When the app is reactivated from Dormant state there is no navigation which could be mapped or redirected...
(I've edited previous answer instead of adding a new one)
I've spend a little time trying to find a solution, and I don't see why your code doesn't run.
In my case it's enough if I do such a change in App.xaml:
private void CompleteInitializePhoneApplication(object sender, NavigationEventArgs e)
{
// Set the root visual to allow the application to render
if (RootVisual != RootFrame)
RootVisual = RootFrame;
// Remove this handler since it is no longer needed
RootFrame.Navigated -= CompleteInitializePhoneApplication;
App.RootFrame.Navigate(new Uri("/passPage.xaml", UriKind.RelativeOrAbsolute));
}
This works on my example which is under the link http://sdrv.ms/1ajH40E
But - I cannot prevent user from seeing last screen when he holds back buton and is chosing to which app return, and then for a blink he can see the last page before leaving the app. I don't know if it is possible to change this behaviour after clicking MS Button:
windows phone change deactivated app image
Second edit
Ok - maybe I've found solution why it sometiems work and sometimes not in your code. After pressing the Start or Search buton the App can go to two cases: Tombstone and non-tombsone. After return different events happen. Code above works with Tombstone case but not with non-tombstone. To work it with the second you need to add (because page is not initialized again) - (of course it can be different solution):
bool afterActivation = false;
private void Application_Activated(object sender, ActivatedEventArgs e)
{
afterActivation = true;
}
private void CheckForResetNavigation(object sender, NavigationEventArgs e)
{
// If the app has received a 'reset' navigation, then we need to check
// on the next navigation to see if the page stack should be reset
if (e.NavigationMode == NavigationMode.Reset)
RootFrame.Navigated += ClearBackStackAfterReset;
if (afterActivation)
{
afterActivation = false;
App.RootFrame.Navigate(new Uri("/passPage.xaml", UriKind.RelativeOrAbsolute));
}
}
Please also ensure of your debug properties in VS: Project->Properties->Debug->Tombstone upon deactiovation checkbox.
You can also find some information here (if you haven't seen it before):
http://blogs.msdn.com/b/ptorr/archive/2010/12/11/how-to-correctly-handle-application-deactivation-and-reactivation.aspx
Seriously. I'm getting really annoyed by Flex. Is there a way to make it wait for an httpservice to get its data without having to use a timer?
At the moment my code looks like this:
protected function loginUser(event:MouseEvent):void
{
if(txtEmail.text == "" || txtPassword.text == "")
{
Alert.show("Please complete all fields!", "Oops!");
}
else
{
user = new User(txtEmail.text, txtPassword.text);
user.login(user);
var loginTimer:Timer = new Timer(1000, 1);
loginTimer.addEventListener(TimerEvent.TIMER_COMPLETE, dispatchLoginEvent);
loginTimer.start()
}
}
When I do user.login(), it sends a request with a HTTPservice from my external AS class. In the result event handler for this httpservice, I set a public variable to true or false, depending on whether the user's credentials are correctly in the DB.
I then use a getter to get that boolean value. However, without the timer, it always returns false because my code is faster than the event result handler. If that makes sense.
So I have to use a timer to stall my application for one second.. But seriously, that doesn't make sense to me. There has to be a better way, no?
I can provide more code if anyone's willing to help me out with this. Thanks.
It seems you didn't completely understand my answer to your other question.
//Note the argument should NOT be a Mouse event, because that would be dispatched by a View.
//you should not have this kind of business logic in a View
protected function loginUser(event:UserEvent):void {
//validate before even trying to create a user, since this
//has the side effect of running an HTTPService call
if (event.login != null && event.password != null) {
user = new User(event.email, event.password);
//these are plain old events dispatched by your user
//Note that strictly speaking a user should not be retrieving itself
user.addEventListener('loginSuccess', onLoginSuccess);
user.addEventListener('loginFailed', onLoginFailed);
} else {
dispatchEvent(new Event('incompleteUserDetails'));
}
}
protected function onLoginSuccess(e:Event):void {
//do your thing here
}
protected function onLoginFailed(e:Event):void {
//trigger your error handling logic here
}
Your UserEvent Class should look something like this:
package service.event {
public Class UserEvent extends Event {
public static const REQUEST_LOGIN:String = 'requestLogin';
//you may have other events that apply to users as well
public var email:String;
public var password:String;
public function UserEvent (type:String, email:String, password:String):void {
//I assume this will be dispatched from a View, given your existing code, so it will bubble by default
super(tyoe, true, true);
this.email=email;
this.password=password;
}
override public function clone():Event {
return new UserEvent(type, email, password);
}
}
}
You would dispatch that from the View based on the values of your email and password fields and listen for it higher up on the display list.
The correct pattern to use is a call back or an event listener on your User object.
protected function loginUser(event:MouseEvent):void
{
...
user = new User(txtEmail.text, txtPassword.text);
// pass a callback function to the login method
user.login(user, function(result:Boolean):void{
// do something with the result
});
}
You'll have to excuse my ActionScript I haven't done any in a little while. But hopefully you get the idea. You should never get your self into a position of setting a timer to poll a boolean on an object in Flex, the answer is always to register a listener or some description.
Incase you are using HttpService object , I think the right way to go around is to use the "ResultEvent" and the "FaultEvent" on this HttpService object to process the data, after it has arrived.
You can see the following examples on how to use the HttpService object so that , it triggers a function after the data has been completely received from the server.
http://help.adobe.com/en_US/Flex/4.0/AccessingData/WS2db454920e96a9e51e63e3d11c0bf69084-7fdc.html
http://help.adobe.com/en_US/Flex/4.0/AccessingData/WS2db454920e96a9e51e63e3d11c0bf69084-7fdc.html#WS2db454920e96a9e51e63e3d11c0bf66651-7ff3