How to make custom event for all SmartParts? - event-handling

There is C# Project (.NET CF) that uses OpenNETCF.IOC.(UI) library.
Actual situation:
In Base Form OnKeyDown event is handled and custom event can be raised (for example if user ESC button pressed). This event can be handled in descendant forms.
After refactoring:
Base Form is now container form. All descendant forms are now SmartParts.
How should I now raise custom event from container form to SmartParts?
// Base form
private void BaseForm_KeyDown(object sender, KeyEventArgs e)
{
// Handle ESC button
if (e.KeyCode == Keys.Escape || e.KeyValue == SomeOtherESCCode)
{
this.ButtonESCClicked(sender, new EventArgs());
}
}
// Descendant form
private void frmMyForm_ButtonESCClicked(object sender, EventArgs e)
{
this.AutoValidate = AutoValidate.Disable;
...
}

I'm not sure I fully understand the question, but I'll try to answer. If you want to raise an event from a child class, but that event is defined in a base class, you should use a "helper" method in the base:
public abstract ParentClass : Smartpart
{
public event EventHandler MyEvent;
protected void RaiseMyEvent(EventArgs e)
{
var handler = MyEvent;
if(handler != null) handler(this, e);
}
}
public ChildClass : ParentClass
{
void Foo()
{
// rais an event defined in a parent
RaiseMyEvent(EventArgs.Empty);
}
}
If you're trying to go the other way, having the parent notify the children, then it's more like this:
public abstract ParentClass : Smartpart
{
protected virtual void OnMyEvent(EventArgs e) { }
void Foo()
{
// something happened, notify any child that wishes to know
OnMyEvent(EventArgs.Empty);
// you could optionally raise an event here so others could subscribe, too
}
}
public ChildClass : ParentClass
{
protected override void OnMyEvent(EventArgs e)
{
// this will get called by the parent/base class
}
}

Related

Make a gameObject follow another gameObject's behavior?

I am controlling a text GameObject. I am performing operations such as SetActive() and changing the text of the gameObject. Now I am duplicating the same object and I want the duplicated object to follow the behaviors of its main gameObject. That is ObjA is parent and ObjB is a clone. If I change the text UI through code of objA, I want objB to automatically change its component. How do I achieve this behavior?
There are multiple ways to do that, but it will always be by code, there is no "authomatism" to do that.
So by code you can make a relation child to parent or parent to child.
One way could be that one:
public class Parent : MonoBehaviour
{
public Child child = null;
public void DoSomething()
{
this.gameObject.SetActive(true);
child.DoSomething();
}
}
public class Child : MonoBehaviour
{
public void DoSomething()
{
this.gameObject.SetActive(true);
}
}
Another fancy way to do that is using delegates, or Actions:
public class Parent : MonoBehaviour
{
public Action OnDoSomething = null;
public Action OnDoSomethingElse = null;
public void DoSomething()
{
this.gameObject.SetActive(false);
OnDoSomething();
}
public void DoSomethingElse()
{
this.gameObject.SetActive(true);
OnDoSomethingElse();
}
}
public class Child : MonoBehaviour
{
public Parent parent = null;
public void Awake()
{
parent.OnDoSomething += ChildDoSometing;
parent.OnDoSomethingElse += ChildDoSometingElse;
}
public void OnDestroy()
{
parent.OnDoSomething -= ChildDoSometing;
parent.OnDoSomethingElse -= ChildDoSometingElse;
}
public void ChildDoSometing()
{
this.gameObject.SetActive(false);
}
public void ChildDoSometingElse()
{
this.gameObject.SetActive(false);
}
}
You can be tempted to pass your own method as Action parameter like Action<Action> but remember that child will call parent method, won't operate on his own. So in this case if you do something like:
public class Parent : MonoBehaviour
{
public Action<Action> OnDoSomething = null;
[ContextMenu("A")]
public void DoSomething()
{
this.gameObject.SetActive(true);
OnDoSomething(this.DoSomething);
}
public void DoSomethingElse()
{
print("Hello");
}
}
public class Child : MonoBehaviour
{
public Parent parent = null;
public void Awake()
{
parent.OnDoSomething += RepeatedAction;
}
public void OnDestroy()
{
parent.OnDoSomething -= RepeatedAction;
}
public void RepeatedAction(Action actionToRepeat)
{
actionToRepeat?.Invoke();
}
}
Will result on StackOverflow exception, cause child will call parent, who calls child, who calls again parent...you can see the problem.
Anyway would be nice to declare an abstract base class that have all the methods, and let both classes inherit from that class, and implement those methods.

Activity handlers don't get removed

I'm trying to get up to speed on using GWT Activities and Places. I'm testing with some source code originally found on this good blog post.
I'm finding the Handlers that get added during bind() never seem to removed. My little understanding of the Activity javadoc had me thinking they should get automagically removed by the time the Activity's onStop() method is invoked.
All event handlers it registered will have been removed before this
method is called.
But each time I click a button the corresponding handler is called n+1 times.
What am I missing? Please let me know if there is more info I can provide.
Here's a relevant snippet from the code:
public class ContactsActivity extends AbstractActivity {
private List<ContactDetails> contactDetails;
private final ContactsServiceAsync rpcService;
private final EventBus eventBus;
private final IContactsViewDisplay display;
private PlaceController placeController;
public interface IContactsViewDisplay {
HasClickHandlers getAddButton();
HasClickHandlers getDeleteButton();
HasClickHandlers getList();
void setData(List<String> data);
int getClickedRow(ClickEvent event);
List<Integer> getSelectedRows();
Widget asWidget();
}
public ContactsActivity(ClientFactory factory) {
GWT.log("ContactActivity: constructor");
this.rpcService = factory.getContactServiceRPC();
this.eventBus = factory.getEventBus();
this.display = factory.getContactsView();
this.placeController = factory.getPlaceController();
}
#Override
public void start(AcceptsOneWidget container, EventBus eventBus) {
GWT.log("ContactActivity: start()");
bind();
container.setWidget(display.asWidget());
fetchContactDetails();
}
public void bind() {
GWT.log("ContactActivity: bind()");
display.getAddButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
GWT.log("Add button clicked");
ContactsActivity.this.placeController.goTo(new NewContactPlace(""));
}
});
display.getDeleteButton().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
GWT.log("ContactActivity: Delete button clicked");
deleteSelectedContacts();
}
});
display.getList().addClickHandler(new ClickHandler() {
public void onClick(ClickEvent event) {
GWT.log("ContactActivity: List clicked");
int selectedRow = display.getClickedRow(event);
if (selectedRow >= 0) {
String id = contactDetails.get(selectedRow).getId();
ContactsActivity.this.placeController.goTo(new EditContactPlace(id));
}
}
});
}
Events registered via. the EventBus passed to AbstractActivity#start() will be unregistered by the time onStop() is called. The event handlers registered in the above bind() method, however, are not registered via the EventBus and are not visible to the abstract base class. You need to unregister them yourself:
public class ContactsActivity extends AbstractActivity {
private List<HandlerRegistration> registrations = new ArrayList();
private void bind() {
registrations.add(display.getAddButton().
addClickHandler(new ClickHandler() { ... }));
registrations.add(display.getDeleteButton().
addClickHandler(new ClickHandler() { ... }));
registrations.add(display.getList().
addClickHandler(new ClickHandler() { ... }));
}
#Override
public void onStop() {
for (HandlerRegistration registration : registrations) {
registration.removeHandler();
}
registrations.clear();
}
}
I found it best to handle registration in the view - make it responsible for only keeping one click hander active for each button.
Instead of:
class View {
Button commitButton;
public HasClickHandlers getCommit () {return commitButton;}
}
..and link to this in the Activity:
view.getCommit.addClickHandler(new Clickhandler()...
Do this in the View:
class View {
private Button commitButton;
private HandlerRegistration commitRegistration = null;
public void setCommitHandler (ClickHandler c) {
commitRegistraion != null ? commitRegistration.removeRegistration ();
commitRegistration = commitButton.addClickHandler (c);
}
}
And the Activity:
view.setCommitHandler (new ClickHandler () ...
Hope that helps.

How to make a server call with out dispatch async instance in gwt

I am using using GWT2.3 with GWTP. Now in this application I need to make a server side call from a non presenter class (So there id no dispatch async instance).
Here is my class
public class NameTokenHandler implements ValueChangeHandler<String> {
#Inject
DispatchAsync dispatchAsync;
#Override
public void onValueChange(ValueChangeEvent<String> event) {
if (event != null) {
String nameToken = event.getValue();
if(dispatchAsync!=null)
{
System.out.println("yes");
} else {
System.out.println("No");
}
History.newItem(nameToken);
}
}
}
Here dispatchAsync is always null. I am getting from where it should be initialized so that I can make a server side call. If there is any other way then please let me know.
Thanks in advance.
You need to inject the NameTokenHandler, so your dispatcher will be injected too.
public class C {
private NameTokenHandler handler;
#Inject
public C(NameTokenHandler handler) {
this.handler = handler;
}
}
This way the handler will be injected to the C class, and your dispatcher will also be injected in the NameTokenHandler. BTW you might need to have a constructor in NameTokenHandler that follows the same pattern (DispatchAsync as a parameter).

Form Method on another thread not invoking the events

I am trying to achieve an update form.
I use a library to open a form when there is an updated file and download using edtFTPNet
In the form I pass the FTP object and start download, in FormLoad i handle two events and i use Thread to StartDownload(). My two events never invoking, i use them to set a progress bar.
public partial class UpdateProgressForm : XtraForm
{
public FTPConnection FtpConn { get; set; }
public string UpdateFileName { get; set; }
public UpdateProgressForm()
{
InitializeComponent();
}
private void OnLoad(object sender, EventArgs e)
{
FtpConn.Downloading += FileDownLoading;
FtpConn.BytesTransferred += FileBytesTransfered;
}
private void FileDownLoading(object sender, FTPFileTransferEventArgs e)
{
progressBar.Properties.Maximum = (int) e.FileSize;
}
private void FileBytesTransfered(object sender, BytesTransferredEventArgs e)
{
progressBar.Position = (int) e.ByteCount;
}
public void StartDownload()
{
FtpConn.DownloadFile(#".\" + UpdateFileName, UpdateFileName);
}
private void OnShown(object sender, EventArgs e)
{
Thread tt = new Thread(StartDownload) {IsBackground = true};
tt.Start();
}
}
Library method calling the Form:
private void DownloadUpdateFile(string updateFileName)
{
using (ProgressForm = new UpdateProgressForm { FtpConn = FtpConn, UpdateFileName = updateFileName })
{
ProgressForm.ShowDialog();
}
}
Any help? Thank you.
Take a look in the designer and make sure you subscribe to those events
Make sure you Instanciate and Show the from from the Main Thread.
Are you sure that the event handlers are not invoked? I think your problem rather is that you try to update the progress bar on the worker thread on which the event handlers are invoke (which is not the thread on which the GUI was created). You should make sure that the GUI updates are performed on the correct thread:
private void FileDownLoading(object sender, FTPFileTransferEventArgs e)
{
progressBar.Invoke((MethodInvoker) delegate
{
progressBar.Properties.Maximum = (int) e.FileSize;
});
}

How do you trigger an event across classes?

I am writing a Class Library that will be used by other applications. I am writing it in C#.NET. I am having a problem with triggering events across classes. Here is what I need to do...
public class ClassLibrary
{
public event EventHandler DeviceAttached;
public ClassLibrary()
{
// do some stuff
OtherClass.Start();
}
}
public class OtherClass : Form
{
public Start()
{
// do things here to initialize receiving messages
}
protected override void WndProc (ref message m)
{
if (....)
{
// THIS IS WHERE I WANT TO TRIGGER THE DEVICE ATTACHED EVENT IN ClassLibrary
// I can't seem to access the eventhandler here to trigger it.
// How do I do it?
}
base.WndProc(ref m);
}
}
Then in the application that is using the class library I will do this...
public class ClientApplication
{
void main()
{
ClassLibrary myCL = new ClassLibrary();
myCL.DeviceAttached += new EventHandler(myCl_deviceAttached);
}
void myCl_deviceAttached(object sender, EventArgs e)
{
//do stuff...
}
}
Probably the easiest option is to add a method to ClassLibrary which raises the event...i.e.
internal void RaiseDeviceAttached(object sender, EventArgs e)
{
if (DeviceAttached != null) DeviceAttached(sender, e);
}
Then, in OtherClass, simply call that method of ClassLibrary.
Another option is to go down the reflection route to trigger the event.