I've added a KeyUpHandler to a Button object as follows:
button.addKeyUpHandler(new KeyUpHandler() {
#Override
public void onKeyUp(final KeyUpEvent event1) {
if (event.isDownArrow()) {
counter++;
}
}
});
However, when I debug with SuperDev mode step by step, there are two calls to the onKeyUp where the initial calls has always counter's initial value (0 in this case) and second call has the latest -maintained- value of counter. The method where I added the logic of onKeyUp is also marked as synchronized. I also tried to call removeHandler() method of HandlerRegistration right after onKeyUp is called. The result was that the mentioned two calls happened after first key up event, but when I did another key up event only one more call happened and further key up events area didn't happen. I assume this is sth related with superdev mode or there is some internal overhead after the compilation. What is the correct way of adding any event handlers at GWT? Do we need to always take care of each handler by calling removeHandler() method of HandlerRegistration?
Re: your comment about multiple calls for click/mouseup/keyup
The browser "helps" for the click handler by firing it whenever any event would effectively click, either mousedown, then mouseup but no move, or various touch or keyboard events. Consider calling preventDefault() on an event you have already handled and you don't want the browser to further look at - for example, if you call this on mouseup and keyup, then those particular actions should never result in click events going off.
Related
I have an observable x.
#observable
double x
Now i have an action which mutates the x
#action
double mutatex(double z){
x=z;
}
Now whenever i call the action, the respective Observer widget gets rebuilt. Is there anyway i can prevent the rebuild of the observer widget upon calling the action. i.e. action method gets called and the mutation happens but the respective observer ignores the action.
That would kinda go against the whole idea of using the Observer, Observable and Action.
You could remove the #action or #observable annotation, but if the UI is rebuilt for a different reason (like screen resize, background and resume, etc) the new result will likely show.
I want to create a rectangle button field (using list).
The "cells" in this field are basically buttons, the only thing I need to change is the OnClick event handler (I want it to check some button properties and take some action according to them).
I did something like this before in MSVS 2013, using C++/CLR, I just wrote the method I wanted to work as an event handler, added event handler variable to the "cell" constructor, and assigned it as a new event handler while "filling" the list.
It looked something like this:
.h
cell(<...>, System::EventHandler^ eh) : {
<...>;
Click += eh;
}
.cpp
List^ list = gcnew List(<...>, gcnew System::EventHandler(^Form1, &Form1::cell_Click));
Mr. Google told me that in C++ Builder inheritance of managed objects is not just writing a colon after the class declaration, it's a process called "Creating component".
Since I don't need to re-use this little piece of code, I don't want to create any packages or use existing. So I create a unit.
The questions are:
Where to write event handler declaration in header?
Where to write event handler implementation in .cpp file?
How do I actually use the written unit in the project I added it to? I mean, can I just declare a variable of the custom inherited type in the project files?
C++Builder uses C++ as its language, not "Managed C++". there is no ^ pointer types and no gcnew, or "managed objects".
To make an event handler easily, select the control in the form editor and press F11. That will bring up the Object Inspector. Select the "Events" tab and then double-click the handler you want to create. This will create the code you need, you just have to fill in the function body.
If you double-click on the control, it's a shortcut to create the most common event handler for that object (which is actually OnClick for a button, so you could just double-click your button).
(In older versions of C++Builder, if you saved your project before typing anything in the function body, it would very kindly delete the handler, which was pretty annoying -- XE5 no longer does that).
I don't quite understand what you are talking about in some of your post - why do you want to inherit from the button? I figured from your opening paragraph that you just want to create a bunch of buttons at runtime, and implement the OnClick handler.
If you mean that you just want to create a lot of buttons at runtime, then you can do it like this:
TButton *b = new TButton(this); // 'this' will be responsible for deleting the button
b->Parent = this; // `this` will be responsible for displaying the button
b->Caption = "hello";
b->OnClick = Button1->OnClick;
// set other properties
AFAIK there is no easy way to clone a button. You have to make a new button like this, and then copy the values you want from another button. Properties you don't set will have their default values.
If you use this method (i.e. make Button1 in the form editor and then copy its OnClick to your other buttons) it is nice and easy. You could actually delete your Button1 after you have used it to auto-generate the OnClick handler and give you the right function signature.
You could also store the pointers to each button in a list , e.g. std::list<TButton *>. Be mindful of button lifetimes when doing this: the fact that the button's Owner is the form means that the form will delete them during the form destruction. You should not try to delete these pointers yourself, and you should not use them during or after the form destruction.
Inside the OnClick handler, you can get a pointer to its Button by doing:
TButton *b = dynamic_cast<TButton *>(Sender);
Then you can use b->Tag or some other property of the button to identify which button was clicked.
This came up time and again for us. After reading such a message, there's nothing intuitive to do and debug.
What this poorly-documented error is trying to say is that you accidentally set up a system in which tracking changes causes more changes.
When Entity Framework changed a property on one of your entities, such as during SaveChanges with identity ID updates, you ran code that changed other tracked properties.
For example, the property that Entity Framework was setting triggered an event, perhaps INotifyPropertyChanged, which perhaps was subscribed to by a BindingSource or some binding list, whose ListChanged event handler was in the UI and triggered a calculation of some other property, and the change tracker detected the second property change.
The simple diagnosis is to place a breakpoint on the SaveChanges() call and immediately after the SaveChanges call(). When the first breakpoint is hit, place a breakpoint on each event handler that could possibly be triggered. (BindingSources are notorious for multiplying each other's events.) Continue debugging. If any breakpoint is hit other than the point immediately following SaveChanges, you know where the problem is.
The simple solution is to set a flag, such as IsSaving, on each side of the SaveChanges call. Then in each misbehaving event handler, do a simple check and do not modify any entities if the DbContext is in the process of saving. Make sure you use finally in case SaveChanges throws an exception that you catch at a higher level:
IsSaving = true;
try
{
await db.SaveChangesAsync()
}
finally
{
IsSaving = false;
}
(One other possibility is that you were changing the entity from multiple threads — never involve the change tracker in multiple threads!)
I had the exact same issue. I had wired to the INotifyPropertyChanged event that created the possibility for a property to change during the SaveChanges() call. I think it is a better practice to unwire the event handlers of you tracked entities when performing dbContext.SaveChanges(), Remove().
I'll explain my experience with this error, hoping it might help someone. And thanks to jnm2 for beautiful explanation.
I had Invoice and Receipt entities, and InvoiceViewModel.
Thie ViewModel was subscribed to Invoice property changed, inside which it was raising CanExecuteChanged events.
I added Receipt to Invoice navigation property and called SaveChanges(), which raised Invoice.ReceiptID property changed and triggered OnPropertyChanged event handler on the ViewModel, which in turn raised all kinds of CanExecuteChanged events.
The problem was that one of the CanCommandNameExecute methods was calling Context.ChangeTracker.HasChanges() which ultimately threw an exception.
How I fixed it?
I followed jnm2, I flagged VM with IsSaving and checked for the flag inside OnPropertyChanged event handler.
Once again, thanks jnm2, and hope someone finds this helpful as well.
Is there an overview about all handlers and their corresponding containers in GWT? Whenever I try to add a handler to a container, I have to check, whether the handler fires an event or not (the JavaDoc does not provide useful information about this). For example a ResizeHandler:
SplitLayoutPanel splitLayoutPanel = new SplitLayoutPanel() {
#Override
public void onResize() {
super.onResize();
System.out.println("onResize");
}
};
splitLayoutPanel.addHandler(new ResizeHandler() {
#Override
public void onResize(ResizeEvent event) {
System.out.println("resize");
}
}, ResizeEvent.getType());
Overwriting the onResize()-method (1. example) gives an information, if the splitter changes, but if I add a ResizeHandler (2. example), I do not get any call of the onResize-method. I don't understand why and don't find the documentation why the handler is not allowed in this container.
I search for an overview of all available handlers, together with their possible containers and event, when they will be fired.
Usually there will be a more specific addHandler method. For example, Button has addClickHandler(ClickHandler). The interface that defines that method is HasClickHandlers, so you can look out for that, for example.
If the event doesn't have it's own addXyzHandler method, it probably won't be supported very well. In that case, it's usually pretty easy to subclass the widget and add support for that handler yourself.
If you add a handler using addHandler() on a Widget, you have to ensure the underlying DOM element could catch matching event. If yes, you also have to tell your Widget to sink this event using
void com.google.gwt.user.client.ui.Widget.sinkEvents(int eventBitsToAdd)
where eventBitsToAdd is a constant from com.google.gwt.user.client.Event.
AFAIK ONRESIZE event is not yet supported natively. So as I said yesterday, you have to implement your mouse handlers and gesture, or override a slider ;-)
I have read where an event is triggered on another thread from the one that created the controls on a Windows Form.
Therefore, the event handler can't directly update the controls (like changing a button's color).
I read the explainations about Invoke or BeginInvoke being needed.
My question: Why can't an event handler just be passed 'this' as an agrument.
'this' being the form whose controls have buttons that want THEIR COLORS CHANGED !! ;)
I can swear I've seen instances where a delegate can take a 'this' - but maybe not...
There's nothing stopping an event handler on another thread just going in and screwing around with the internal state of the button.
However, it causes bad things to happen - as an example, what would happen if you changed a property of a control while something else was also trying to write to it?
Only one thread should be screwing around with the internal state of an object at a time - if you call methods directly on that object from another thread, you can't guarantee that something else isn't doing the same.
Invoke gets around this by not calling it directly - instead it says to the thread that 'owns' the object "Hey, could you call this method on that object when you've got a moment?", thus ensuring that the method is only called when the object is in a consistent state.
If you are handling an event with an instance method in the form, you already have a "this" parameter. Say something like this:
Public Class MyForm
Inherits Form
Private port As New SerialPort()
Private Sub RegisterHandlers()
AddHandler port.DataReceived, AddressOf ProcessData
End Sub
Private Sub ProcessData(ByVal sender As Object, ByVal e As EventArgs)
If Me.InvokeRequired Then
'marshal to required thread
Exit Sub
End If
'do stuff on the form thread
End Sub
End Class