RelayCommand for handling changes in TextBox - mvvm

I am new to MVVM and MVVM-light.
I always see RelayCommand being used to handle Button's Command action. So it will invoke a service operation aysnc.
My question is how can I use it to handle TextBox changes in the text it is holding? How can I relay that change to the Server side using service? Should I use RelayCommand too?

Typically it's not needed. If you bind the TextBox Text property to a member of your viewmodel and set its UpdateSourceTrigger to PropertyChanged then your bound member will get called as soon as the value of the textbox changes i.e. whenever the user presses a key:
private string _myString;
public string MyString
{
get { return this._myString; }
set { this._myString = value; /**** user pressed a key, respond to it here *****/}
}
It's also possible to set up an Event Trigger and intercept the windows messages directly, but I suspect that's not really what you need here.

Related

Set OnAutomaticHitTest and OnInteractiveHitTest during runtime

I'm placing my Plane Stage and Plane Finder and setting the attributes at runtime, but there are two attributes I can't figure out how to set: OnAutomaticHitTest and OnInteractiveHitTest.
I saw that it expects something of the type HitTestEvent, but i can't figure out how to set my custom function here.
Can someone Help me?
You can find the documentation for the PlaneFinderBehaviour here
Essentially, you don't actually define these attribute but you use them to fire events.
For example:
public class CustomPlaneFinderBehaviour : PlaneFinderBehaviour
{
public void CustomIntPerformHitTest(Vector2 screenPosition)
{
//Triggered on interactive hit test
}
public void CustomAutoPerformHitTest(Vector2 screenPosition)
{
//Triggered on automatic hit test
}
}
Then in the inspector you are able to define the events, by pressing the plus button and choosing the current script in the box. It then gives you the option to change the function that is called.
Here on interactive hit test has been defined and automatic hit test has not:
You need to use Unity's AddListener call
void HandleHitTest(HitTestResult htr)
{
//Handle Test Here
}
planeFinderBehavior.OnAutomaticHitTest.AddListener(HandleHitTest);

GWT input event on TextBox

Given the following code:
TextBox tb = new TextBox();
tb.addValueChangeHandler(new ValueChangeHandler<String>() {
#Override
public void onValueChange(ValueChangeEvent<String> event) {
Window.alert(event.getValue());
}
});
onValueChange will be called if the TextBox loses focus. I am trying to have it called whenever the input value changes. The solutions I have read all involve handling the keyup and paste events such as in this answer. How to build a Facebook-style input box in GWT Hasn't this been addresses in GWT 2.5.1? Is there a way to bind to the native input change method? Another widget or using the UI framework would be acceptable if they have this functionality
The only way in GWT is to bind to the key down/key up and paste events.
Please send a patch to add support for the input event (using addBitlessDomHandler): http://www.gwtproject.org/makinggwtbetter.html, it should be rather easy (add a acase in DOMImpl) and has good chances to make it in (and if sent early enough, would have good chances to ship in GWT 2.6)
The solution is use the right event and that is the input event, so look how to hook on it, there are many ways to do it. Because I work with elements and not with Widgets this the code that I use it:
Element input = Document.get().getElementById("my-input");
DOM.sinkBitlessEvent(input, "input");
DOM.setEventListener(input, event -> GWT.log("Event!"));
You can just use addChangeHandler() and onChange, tb.getValue().
I used the following to detect when the value of a textbox changes. Just bare in mind this only detects if the text box goes from empty to full or full to empty. This was done to try reduce async calls to the server to validate the input
#UiHandler("notes")
#SuppressWarnings("unused")
public void notes(KeyUpEvent event) {
if (!areNotesCaptured && !notes.getText().isEmpty()){
fireLeaveSelectionUpdatedEvent();
areNotesCaptured = true;
} else if (areNotesCaptured && notes.getText().isEmpty()){
fireLeaveSelectionUpdatedEvent();
areNotesCaptured = false;
}
}

GXT get value of TextArea without focus loss

I have a GXT 3 TextArea on which I catch copy-paste events. On this event, I would like to get the text that is inside the textarea.
Problem : the textarea still has the focus so the value is not updated. Hence, getValue() returns an empty string...
I tried to call getValue() getCurrentValue() flush() validate().
I also tried to extend TextArea to have access to blur() method and call it before getting the value : it makes no difference.
Any solution? (even solution with GWT components would be appreciated).
Without seeing the code you have, it is difficult to say for sure. But at a guess, you are listening to the event, and invoking getCurrentValue() (the correct call in this case) right away.
This is wrong - it is possible for the event handler to call preventDefault(), to cancel the default behavior of that event for most events that can take place. After the event handler returns, only then does the browser actually perform the action (paste or drawing the key that was pressed). The solution to this is to wait a moment before trying to read, to wait until after the action has been completed. The simplest way to achieve this is to schedule a deferred command after the event has occurred, and read the field's value then.
//in the event handler of your choice...
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
String pastedValue = field.getCurrentValue();
//do something with the value now
}
});
Before getting the value you can call
yourTextField.finishEditing();
After it method getValue() should return the value of the field. If you would like to keep this field focused after getting the value you can always call
yourTexField.focus();

GWT How discard changes on a Editor

I there a way of Editor discards changes made on its properties? This on client side. No persitence.
I have:
public class ClaseEditor extends PopupPanel implements Editor<ClaseProxy> {
#UiField ValidatedTextBox tema;
#UiField ValidatedTextBox catedratico;
}
I use this editor on a ListEditor as u know there are a list of editors in your
ListEditor<ClaseProxy, ClaseEditor>
If user create one, its okay, then if user edit it. i have a save or cancel options, i save ok, just hide the editor and changes made are ok.
But in user clicks Cancel and if there was some changes on the properties the editor flush(lazely) that changes to the proxy.
Yes i can store the start value on a string then restore with setValue() on the texboxes. But there is some other way (Editor API) that prevents this?
Thank you
If you are using a SimpleBeanEditorDriver, you can do a new call on the edit method, without calling flush first.
The SimpleBeanEditorDriver class reads from the bean into the editors on edit, and from the editors into the bean on flush.
If you don't want to revert all the editors, but only one of them, remember to call flush on every accepted editor change, in order to be able to restore to the last flush point. Note that a flush call is local and doesn't necessarily have to correspond to a call to the persisting layer.
Example code
private Bean currentObject;
/**
* Start editing the given object.
*/
public void edit(Bean object) {
this.currentObject = object;
this.driver.edit(object);
}
/**
* Call this every time an editor is in a consistent state.
* (e.g. onBlur event if validation succeeds)
*/
private void save() {
this.driver.flush(); // saves editors' state into currentObject
}
/**
* Call this to cancel changes on all editing editors.
* (e.g. onBlur event if validation fails)
*/
private void revert() {
this.driver.edit(currentObject); // reloads currentObject into editors
}
/**
* Stores all pending changes to the server.
* Remember to validate all editors.
*/
public void commit() {
Bean object = this.driver.flush();
Server.persist(object);
}
Yes. On the cancel button, do a fire() without building any request. What the editor does never effects the original proxy, it is immutable. The flush only gives you a copy (unless you are using the RequestFactoryEditorDriver then it returns the context you sent into it with the driver.edit(proxy,ctx) . The fire() without a request clears the edit proxy copy if the user wants to edit again it won't get an error that it is already being editted.

pause viewmodel process for user input

I've been looking at a view examples of the typical "raise dialog from viewmodel" problem, noting 3 main solutions:
use attached behaviors
use a mediator pattern
use a service
I'm getting a bit bogged down though and struggling to find a solution that easily fits into my problem space - which is a very simple file copy problem:
My viewmodel is processing a loop (copying a list of files)
When a file already exists at the destination I need to raise a modal dialog to get confirmation to replace
The vm needs to wait for and receive confirmation before continuing
The "modal dialog" is actually not a new window but a hidden overlay in my MainWindow, as per http://www.codeproject.com/KB/WPF/wpfmodaldialog.aspx (thanks Ronald!)
I'm mostly there but the biggest struggles I have are:
- how to pause the loop in the viewmodel while it waits for input
- how to get input back to the viewmodel within the loop so it can carry on
So far I'm leaning towards the service solution because it seems a direct method call with a return that the vm must wait for. However, it does mean the service needs to tie directly to the view in order to make an element visible?
If anyone can post some simple code that deals directly with this problem I (and the net) would be very happy! Thanks!
For example, you have a service called IDialogService with the following interface:
public interface IDialogService
{
bool ConfirmAction(string title, string confirmationText);
}
As you mentioned, in order for the service to be able to show the actual dialog it needs to have a reference to the view that will show the actual overlay element. But instead of directly referencing the view I prefer to reference it via an interface. Lets call it ICanShowDialog and it will have the following members:
public interface ICanShowDialog
{
void ShowDialog(object dialogContent);
void HideDialog();
}
This interface will be implemented by your view that owns the dialog overlay (e.g. your main window).
Now the interesting part: suspending the code execution while the dialog is shown. First of all, I would recommend you not to use overlay elements but use usual windows if possible. Then you will not have that problem. You can style the dialog window so it will look just like the overlay element.
Anyway, if you still want to use overlay elements then you can do the following trick to suspend the code execution:
Here is pseudo code of the ConfirmAction method of the IDialogService inteface:
public bool ConfirmAction(string title, string confirmationText)
{
ConfirmationDialogView dialogView = new ConfirmationDialogView(title, confirmationText);
DialogShower.ShowDialog(dialogView); // DialogShower is of type ICanShowDialog
while (!dialogView.ResultAvailable)
{
DispatcherUtils.DoEvents();
}
DialogShower.HideDialog();
return dialogView.Result;
}
Here is the code of DispatcherUtils.DoEvents() (that was taken from here: http://dedjo.blogspot.com/2007/08/how-to-doevents-in-wpf.html):
public static class DispatcherUtils
{
public static void DoEvents()
{
DispatcherFrame f = new DispatcherFrame();
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Background,
(SendOrPostCallback)delegate(object arg) {
DispatcherFrame fr = arg as DispatcherFrame;
fr.Continue=True;
}, f);
Dispatcher.PushFrame(frame);
}
}
But I must warn you. Using DoEvents can result in some subtle bugs caused by inner dispatcher loops.
As an alternative to suspending the code execution while a dialog is shown you can use callbacks:
public interface IDialogService
{
void ConfirmAction(string title, string confirmationText, Action<bool> dialogResultCallback);
}
But it will not be so convenient to use.