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
Related
I am trying to raise an event in Matlab. It is working, but not as i expected. What is going on is that the source object is passed as parameter do the event handler and i can't access my object properties inside the event handler.
Here is my class:
classdef MyClass < handle
properties
Name = 'a';
end
events
Changed
end
methods
function obj = MyClass(current)
if exist('current','var')
addlistener(current,'Changed',#ChangedHandle);
end
end
function obj = Change(obj,value)
notify(obj,'Changed');
end
function obj = ChangedHandle(obj,value)
disp(obj.Name);
end
end
end
These are the command lines to reproduce whats going on:
a = MyClass();
b = MyClass(a);
b.Name = 'b';
a.Change(3);
This is returning "a" and i want it to return "b".
Regards
The listener callback you specify receives details of the object raising the event. The fact that the listener has been created during the creation of a different object is not an intrinsic property of the listener – unless you effectively embed this in the design of your callback.
In your example, #ChangedHandle only works as a callback because it happens to be a method of the class current belongs to. If a and b belonged to different classes the problem would be more obvious: if ChangedHandle was a method only of a, it wouldn't know anything about the Name property of b. And if only a method of b, the listener bound to a would have only the function handle without any reference to the instance b of the class to which ChangeHandle belongs.
As described in the listener callback documentation you can use a method of the specific object instance current as an event listener using the syntax #current.ChangedHandle.
This method then receives callback arguments in the format callbackMethod(obj,src,evnt), so you need to add an argument to the definition of ChangedHandle. The first argument obj will be the instance referenced by current when the listener is created, so the line disp(obj.Name) will then produce the intended result without modification.
The reference to a received by the callback in the example will still be passed to the new callback – this is a fundamental behaviour of listener callbacks – but it will now be accessible from the second argument src.
In your addlistener code you are not telling the listener which object you want to call the method on, so what Matlab does it will apply the listener to the current object since thats all that was passed into the function, you can check this by changing the code to:
addlistener(current,'Changed',#(h,evt)current.ChangedHandle);
if you want it to run the code for the other class b (obj), then you use:
addlistener(current,'Changed',#(h,evt)obj.ChangedHandle);
I have a main form that creates a second form dynamically at runtime. When calling the create method the owner of the second form is set to the main form. When i close the application the FormDestroy of the main form is called before the FormDestroy of the second form.
Normally i would suggest that the owner destroys all owned forms and after that destroys itself.
Why is the form destruction order that way?
A form's OnDestroy event is fired from its BeforeDestruction method.
A component destroys its owned components from its destructor.
The BeforeDestruction method executes before the destructor and hence the behaviour that you observe.
It is the case that owned components are destroyed before their owner. Imagine it was the other way around. If the owner was destroyed first, the list of owned components would have been destroyed and there would be no way to destroy the owned components.
What is confusing you is that when an owner begins its destruction process, a number of things happen before it reaches the point where it destroys any owned components. And one of those things is to fire its own OnDestroy event.
The call tree for the main form's destruction looks a little like this:
TMainForm.BeforeDestruction
TCustomForm.BeforeDestruction
TCustomForm.DoDestroy
TMainForm.FormDestroy --> this is your main form's OnDestroy event handler
TMainForm.Destroy
TForm.Destroy
....
TComponent.Destroy
DestroyComponents; --> owned components are destroyed here
....
By the time the main form has called DestroyComponents from inside its TComponent.Destroy, all the owned components have been destroyed. Then the main form completes its destruction process and then it too has been destroyed.
I am developing using Entity Framework and WPF, and I am encountering some errors and I don't know why. When saving a record (using a BackgroundWorker), I set the entities change tracker to nothing (null), attach the record to a new disposable context, save it, detach, and dispose of the context.
Saving a record fires and event in theMainViewModel of the program that the other ViewModels (including the one that is saving) need to refresh their entities to reflect changes.
Private Sub _saveRecordWorker_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles _saveRecordWorker.DoWork
Using MyContext As New RVShippingEntities
Dim MyShipment = CType(ShipmentRecord, IEntityWithChangeTracker)
MyShipment.SetChangeTracker(Nothing)
MyContext.Attach(MyShipment)
MyContext.Detach(ShipmentRecord)
End Using
End Sub
The Refresh background worker is similar, but it has a Do While block to keep it from interfering with the save worker (which doesn't appear to be working; hence the post). When I save (and it subsequently refreshes) I get the following error:
The calling thread cannot access this object because a different thread owns it.
I thought that with theDoWhile block, it would wait (and when I step through it does) until the save thread finished, and all would be good. But it would seem that something (either the main thread or the save thread) is still doing something that is interfering.
Is there a better way of doing this? Am I doing it in a goofy kludgey fashion? Any help would be appreciated.
(Apparently Firefox recognized kludgey as a word. Interesting)
So, 3+ months and nary an exception so far in relation to Entity Framework. I am going to call this the answer.
Parent Views (in my case Company, Customer, Shipment) have a context which is passed to child Views as necessary (Addresses, Phone Nums, Email Addresses, for Company and Customer; Packages, Contents, for Shipments). Anytime a context can't save changes or what have you (db disconnection is most common cause), the context is disposed, a new one instanced, the entities are re-attached, set to modified (based on custom change tracking which I do for UI), and changes are saved.
For performance tests I need a way to measure the time needed for a form to load its definition from the DFM. All existing forms inherit a custom form class.
To capture the current time, this base class needs overriden methods as "extension points":
start of the deserialization process
after the deserialization (can be implemented by overriding the Loaded procedure)
the moment just before the execution of the OnFormCreate event
So the log for TMyForm.Create(nil) could look like:
- 00.000 instance created
- 00.010 before deserialization
- 01.823 after deserialization
- 02.340 before OnFormCreate
Which TObject (or TComponent) methods are best suited? Maybe there are other extension points in the form creation process, please feel free to make suggestions.
Background: for some of our app forms which have a very basic structure (with some PageControls and QuantumGrids) I realized that it is not database access and other stuff in OnFormShow but the construction which took most of the time (around 2 seconds) which makes me wonder where this time is spent. As a reference object I will also build a mock form which has a similar structure but no code or datamodule connections and measure its creation time.
The best place for "instance created" is TObject.NewInstance.
In Delphi 2009 the best place for "before deserialization" is TCustomForm.InitializeNewForm. If that isn't available override TCustomForm.CreateNew and grab the time immediately before it returns.
You're correct that the best place for "after deserialization" is TComponent.Loaded.
For "before OnFormCreate" override TObject.AfterConstructor and get the time immediately before calling the inherited method. If you want the total construction time, grab the final time after that inherited call returns. That will include both the OnFormCreate and any initial activation time. Alternatively, you could just override TForm.DoCreate, if you're not overriding that anywhere else.
Let's assume that the loading of the form's DFM is the main time part of the construction of the form, we could add a constructor to the form like:
constructor TMyForm.Create( AOwner: TComponent );
var
S, E: Int64;
begin
QueryPerformanceCounter( S );
inherited Create( AOwner ); // here is the dfm loading
QueryPerformanceCounter( E );
// Log using the classname and the time in QPC ticks.
LogQPCTime( ClassName, E - S );
end;
I couldn't find any reference on how to use a parent form element in a subclassed form. May be because it's obvious to everyone but me. It's got me stumped. This is what I tried.
At first, within my form constructor I called
parent::__construct($options = null);
then accessed the parent elements like this
$type = parent::setName($this->type);
The problem was that ALL the parent form elements would display whether explicitly called or not. Someone said, "don't use __construct(), use the init() function instead. So I changed the constructor to init(), commented out the parent constructor, then ran the form. It bombed saying it couldn't pass an empty value for setName(). I commented out all the seName() calls and the form ran, but only displayed the elements instantiated in the subclassed form.
My question is this: If I don't use the parent constructor, how do i get and use the parent's form elements?
Solved: Since the constructor was switched to init, the call to the parent also needed to be switched. Easy for someone with php background. Not so much for one who doesn't.
Use
parent::init();
Solved: Since the constructor was switched to init, the call to the parent also needed to be switched. Easy for someone with php background. Not so much for one who doesn't.
Use
parent::init();
You should learn OOP principles first. Obviously you have no understanding of it whatsoever. You need to call parent::init() in you Form_Class::init() method as you wrote, but why? Because otherwise the parent method is not called and is overriden by the From_Class method.
Other thing is that when you have a parent class "SuperForm" with input and submit, then your "SuperForm_Subclass" would have the same elements assigned. There is no need to use "parent::*" to access element (only exception would be if you used static SuperForm variable to store them - which makes no sense).
You can easily use $this->inputElement and $this->submitElement inside your SuperForm_Subclass like you would in the SuperForm class.
In your example you could used the __contruct() as good, but with the same condition of calling the parent constructor. You would be able to access elements generated there too...