Event is null

Topics: CAB & Smart Client Software Factory
Jan 8, 2007 at 5:06 PM
Hi,

I have a class defined in my SCSF project(Shell application) and i have declared one event publication.

When i try to rasie this event, it shows the event is null.

Do i need to add this class to the root workitem. This class is loadedby the shell main window. Infact, i am facing the same issue, i.e. not able to raise events form the shell mainwindow too.

Can someone let me know how to get this working

Regards/Srinivas


Jan 8, 2007 at 6:55 PM
lsvasu,

To make sure we've got the basics out of the way, let me verify a few things first.

You're trying to publish this event in ShellForm.cs and NOT ShellApplication.cs, correct?

Next, in ShellForm.cs, make sure you have the Event Published this way:

At the top of the class, you must have this code:
EventPublication("YourEventTopicName", PublicationScope.Global)
public event EventHandler<EventArgs> YourEventName;


Then, in your method, you have the code set up in this way:
if (YourEventName != null)
{
YourEventName(this, new EventArgs<string>("Whatever text or object goes here));
}


Finally, supposedly, the Event will be null if there are no subscriptions it. My testing shows contrary to that, but--regardless--you may want to make sure you have a subscription to the event, the topic names match EXACTLY, and that the subscription falls into the scope of the raised event.


One assumption I’m making is that your using statement includes “Microsoft.Practices.CompositeUI.EventBroker”. You couldn’t compile otherwise.
Jan 11, 2007 at 6:06 PM
Make sure declare the subscription method as public otherwise it never gets called.
Jan 11, 2007 at 7:23 PM
I'm actually running into the same problem, although I'm trying to publish/subscribe to events between presenters/views. Here's the code I'm doing:

In the presenter of my first screen, I have:
EventPublication(EventTopicNames.CurrentCustomer, PublicationScope.Global)
public event EventHandler<DataEventArgs<Customer>> CurrentCustomer;

In the same presenter I have:
public void OnCustomerChanged(Customer customer)
{
OnCurrentCustomer(customer);
}

And then:
protected virtual void OnCurrentCustomer(Customer customer)
{
if (CurrentCustomer != null)
{
CurrentCustomer(this, new DataEventArgs<Customer>(customer));
}
}
In my second view's Presenter, where I want to work with the customer, I have:

EventSubscription(EventTopicNames.CurrentCustomer, ThreadOption.UserInterface)
public void OnCustomerChanged(DataEventArgs<Customer> eventArgs)
{
_currCustomer = eventArgs.Data;
}

I put a break point on _currCustomer and it doesn't ever hit it, and the program crashes with an exception.

Anyone see what the problem could be?
Jan 11, 2007 at 7:26 PM
It's because your method signature in your presenter that is handling the event is missing the 'object as sender' arg.
Jan 11, 2007 at 9:24 PM
Well, I added the object sender to the signature, (which was dumb in the first place as my other event had it) but it still is not working. Just curious, but it should break if I put a point on the EventSubscription function? If it should break, it's not firing the event, which is also strange since the subscription I have in the module controller to open a view works fine.

Is there anything else visibly wrong with my CurrentCustomer implemetation, or any other ideas anyone has?
Jan 15, 2007 at 7:53 PM
I've seen situations in our app where an event doesn't get received by the subscriber. (Although usually nothing happens, rather than an exception. If you would post your exception message that might help figure out the problem.)

Every time, I've found that the problem was the object where I was subscribing had not been added to a WorkItem. So in your second view's presenter, make sure that the presenter is being created in the proper way, with a CreateNew attribute inside the view. Also, when debugging, sometimes it helps to dive into the CAB code, you might be able to decipher the event call stack and see if your presenter is listed as one of the subscribers to that event.

Events are the toughest thing to debug, good luck!
Jan 15, 2007 at 7:55 PM
I almost forgot, also make sure that the View is labeled as a SmartPart and added to a WorkItem using syntax similar to:

WorkItem.SmartParts.AddNew<View> etc...
Jan 15, 2007 at 10:32 PM
Interestingly, I debugged the two events I have, and I think I know where the problem is. I have one event publication to show a view, and one event publication to keep track of the current customer. The eventpublication that I have to show the view is in my first views Presenter, but is subscribed to in the ModuleController and works just fine. My other eventpublication to keep track of the customer is in the same presenter, but I want to subscribe to it all over the place (any place I want to see if the customer has been updated and I want to work with the new customer) so I have one subscription in my second views presenter. I traced through the event to show the view, and found that after it gets the handlers and workitem (my modulecontroller), it goes to the modulecontroller and does what it's supposed to. When I step through the other event, it gets the handlers and workitem (my modulecontroller) and then goes to the modulecontroller looking for the subscription (at least I think this is what happens).

I looked through the bank and appraisal references and they have events that are published and not subscribed to in the modulecontroller, yet I don't know why their events would work and mine aren't. The only thing I noticed was in the appraisal reference, they have a service that they use to handle some of the events. I don't know if I need to implement a service in order to get this to work, but I really can't figure out what else to do...
Jan 16, 2007 at 7:51 PM
Can anyone help me out? I feel like I'm so close, but I also feel so stumped :(
Jan 16, 2007 at 8:22 PM
The purpose of the loosely coupled Events is to be able to publish once and subscribe pretty much anywhere else throughout CAB. so I think you've got the right premise there.

However, I think pfountain is right in saying that events are the toughest thing to debug. Any possibility you could zip up the project (or a sample one that has the same problem) and make it available for us to take a quick look at?
Jan 16, 2007 at 9:08 PM
Raymond:

Here is my one main module. http://siraris.net/PatientModule.rar

I'd really appreciate some help. I've only been at this for about a week and a half now, so go easy on me :).

The CurrentPatient event doesn't seem to fire, even though the ShowPlanOfcare one does. I just want to be able to access the current patient from anywhere in the project.
Jan 16, 2007 at 11:28 PM
ok Siraris. Before I start, I wasn't actually able to get your code to compile. It's complaining about the AdventureWorks namespace.

Is there an AdventureWorks sample project I'm not aware of or does your test project just connect to this database? Just curious :)

Nonetheless, let me tackle a couple of issues:

First, although you have properly instantiated your EventPublication, you actually have to make a call to it from within that same class (in this case, it's PatientViewPresenter)

Look at the example SCSF solution BankTellerWorkbench
Source\src\BrancSystems\Module\ModuleController.cs

See the EventPublication for CustomerWorkItemCreated?

Notice, that in addition to that declaration, there is also a call to it in the routine "private void OnCustomerWorkItemCreated" there is this code:
if (CustomerWorkItemCreated != null)
CustomerWorkItemCreated(this, new EventArgs<WorkItem>(entryWorkItem));

So, you would need something like this:
if (POCDoubleClick != null)
POCDoubleClick(this, new EventArgs<DictionaryEventArgs> yourVariableHere)


In your subscription, "Thread = ThreadOption.UserInterface" is not necessary. Just use "ThreadOption.UserInterface"


Also, and this is more from a philosophical POV, the Presenter and the View are aware of each other. The Presenter normally communicates with the view via the Interface (e.g. IPatientView) and the view communicates with the Presenter directly (e.g. this._presenter)

So, although what you're doing should theoretically work, it'll probably be easier if they communicate as described above. I imagine your just trying to get proof-of-concept though...which is something I can totally relate to.

My First Goal is usually Make it work Then, my next is Make it work right


Anyway, I have to run, but if I get a chance tonight I'll take a look at some more of your code to see if there's any other pointers I can give.

Hopefully, this will at least help you get a little further in your CAB adventure.

One Final Note: Try to use the EventTopic Names as much as possible for your Events Names. This prevents you from having a typo on things such as "topic://PatientModule/POCDoubleClick". You can instead use "AdventureWorks.PatientModule.Constants.EventTopicNames.ShowPlanOfCare" or something shorter if you put the using statement at the top.
Jan 17, 2007 at 1:35 AM
Ray - I was just about to ask if we were looking at the same code, when I looked at the rar file itself, and found that something weird is going on. If you look in the root folder of the rar file, there is a bunch of folders and classes, but also in there there is a PatientModule folder. For whatever reason, the files in the root PatientModule folder that you look at when you first open it is very old code, and I have no clue how it got there.

So, open the rar, then in the PatientModule folder open the PatientModule folder under that, and that has all my updated stuff.

I was extremely confused, as I have done everything you mentioned in your post! My namespace is also called Test, and not Adventureworks, and I changed that 2 or 3 weeks ago a day after I started on this. Very strange.

I'll need to look at that at the office tomorrow. But yes, if you can look at the REAL PatientModule folder in there, it should make a lot more sense :)

And if anyone else could too, who perhaps had some time, I'd appreciate it :) This is very frustrating!

**BTW If it helps, I know exactly what is wrong. The event broker is not finding the subscription, I assume because it's looking in the ModuleController, and there is no subscription there. I'm just confused why it can't see it in the Presenter that I have it. I'm guessing it has something to do with WorkItems, which I am still not completely at grips with at this time.
Jan 17, 2007 at 4:30 PM
Ok, yes. That code conforms much more to what we were talking about.

Now the good news: I was able to make it work.

I created a new SCSF solution, added your module and commented out or adjusted references where necessary.

You can download what I have here:
http://tinyurl.com/2cn3fp

If you run it, you should see a new Menu Item called "Launch Global Events". You won't really notice anything unless you put breakpoints at all the EventSubcriptions in the solution. It does hit all those subscriptions though.

Now for what I suspect may have been the problem:
Did you add the module name to your profilecatalog.xml? It's a simple setup issue that, if not done, prevents your project from being loaded into the CAB framework.

That's really all I had to do and, once done, the Patient Module project was ready for all things CAB.

Notice I also included the CAB visualizer in this solution. This is a very useful tool for figuring out what's loaded into CAB. (In order for the Visualizer to work, notice the entries in the App.Config file)

Since I'm not able to see your full solution, that's my best guess. If not, well hopefully the attached project will help you find what you need.

--Ray

P.S. Don't be frightened by WorkItems. They're just a tree scoping containers. They are used to hold your Smart Parts, Workspaces, Services, etc. They are also self-disposing scoping boundary. When you dispose it, it disposes all its contents as well.
Jan 17, 2007 at 7:50 PM
Raymond -

Wow, it does work! I actually can't go into work today (had an ignition coil on my car blow on the way, actually) so I unfortunately can't test it myself until tomorrow (or if they finish my car early and I can get in). I am pretty sure I put the module in the profile catalog, well, I used the guidance package to put my module in the project, so that should have put it in the Profile Catalog, correct? I'm actually pretty positive that it's in the Profile Catalog.

The only thing that I noticed that you added was:

EventSubscription(EventTopicNames.CurrentPatient, ThreadOption.UserInterface)
public void ShowPatientView(object sender, EventArgs e)
{
PatientView view = WorkItem.SmartParts.AddNew<PatientView>();
//WorkItem.WorkspacesWorkspaceNames.PrimaryWorkspace.Show(view);
}

And I'm wondering if that did it, as I said, when I traced through my project to see what was happening, it looked as if it was looking in the ModuleController for the subscription, and when I put the CurrentPatient event into my ModuleController and put a breakpoint, it hit the event, yet when it's in the PlanOfCareViewPresenter, it doesn't hit the breakpoint. The thing is, if I put a break point in the Event in the PlanOfCareViewPresenter in your project, it hits it. It just doesn't make sense to me because it should monitor events across all classes, correct? And if it is able to see my event to show the plan of care, the patient module is obviously included in the profile catalog, correct? Is there something that I need to add to my ModuleController to make this work, or to my WorkItem in order to make this work?

The only other thing I see is what you added to the Infastructure.Layout, which is the same thing I am doing in the PatientViewPresenter, for the most part. Would you calling it from the Infastructure.Layout make a difference?

RE: Workitems - I'm not really "scared" of them, more like I don't know the entire ins and outs of them yet. But I think I'm getting much more of a grip :).

Jan 17, 2007 at 9:29 PM
Ok, I think that last message has put us on the same page.

"...used the guidance package to put my module in the project, so that should have put it in the Profile Catalog, correct?"

Yes, that is correct so that won't resolve your issue.

However, I did notice one other thing: In your module controller for the Patient.Module, you do not have a call, nor a method, to AddViews. You must add your smart parts to your WorkItem before CAB will do anything with them.

So, do this in your Patient.Module ModuleController:
1. In the Run() method, add a call to a method called AddViews()
2. Add a "private void" method called AddViews and put the following lines of code in it:
  • IPlanofCareView planofcareView = this.WorkItem.SmartParts.AddNew<PlanofCareView>("RaysPlanOfCareView");
//Optional code to display the smart part immediately:
this.WorkItem.WorkspacesWorkspaceNames.RightWorkspace.Show(planofcareView);*

Now when you launch the event, the Plan of Care presenter will be able to subscribe to it.

Whew! Hope that does it! :)

Here's my project with the update:
http://tinyurl.com/2dpnsl
Jan 17, 2007 at 11:31 PM
Ray -

You're the man :) I owe you one. This is something that just flew totally off my radar, never even came up once in my research. I hate when it's little things like this, HATE it!.

I really appreciate it, and it's wonderful to have someone like yourself on these forums. I hope you stick around for a long time!
Jan 18, 2007 at 2:28 PM
"...I owe you one."

Nah...just glad to help! :)

Jan 18, 2007 at 10:41 PM
Well, Ray, I have bad news, it worked but didn't work. :(

It works in the sense that it subscribes to the event and I actually get into the event and it sets the variable. The problem is, it sets _currPatient in the planofcarepresenter to the correct patient, and then exists out of the event and goes on to the ShowPlanOfCareHandler. When it gets there, _currPatient gets set to null somewhere (I can't see where it happens) and it crashes trying to set the fields on the PlanofCare when it loads.

For all intensive purposes, shouldn't _currPatient keep the value it gets in my CurrentPatient event? I watched the thread watcher, and it stays on the same thread throughout the program, it's not like it's a different thread. I'm not setting _currPatient anywhere else.

I assume it's setting _currPatient as a reference to the Patient I find, correct? Do I need to create a copy method to put the Patient I find in the _currPatient variable? Is it going out of scope?

I've tried debugging for the past 2 hours and I can't see where or why it would be getting set to null. Any ideas? Suggestions? I'd appreciate it.

BTW If it's ok with you, maybe we should talk over email, as to not clutter up these messageboards. My email is Siraris AT Comcast dot Net, if you want to give me a bit more help (i'd really appreciate it). Or if anyone else can lend a hand.