简体   繁体   中英

How to handle events across WPF pages

I use C# for creating different types of "Wizard-like" applications. In the beginning I was using WinForms and a tab-control to guide users through different choices, but now I'm using WPF and pages. This way it's much cleaner and easier to modify. It works just as I need it to, but once thing I'm now struggling with are events.

For example I have the following structure (a photo booth application):

- MasterPage.xaml
|-- Welcome.xaml
|-- Photo.xaml
|-- Preview.xaml
|-- Done.xaml

In this case I create a MasterPage that holds the overall theme and a frame that can hold the content (pages). The welcome-page is loading on startup, the user clicks next, takes a picture and is automatically transferred to the preview page. From here the user can either retake the photo or quit and be presented with the "Done" page. I hope that somewhat makes sense...

Anyway, my issue is that I don't really know how to use objects that fires events. In this case I have a CameraHandler object that has multiple events like ImageTaken or PreviewUpdated.

At first I defined a new instance of CameraHandler each time the pages "Photo" was loaded and disposed of it when the page_unload got triggered. In order to pass the image to the next page I just used the event ImageTaken to save the image to a user object for that current session. However, if a user kept taking pictures and then retake it, the CameraHandler would be created and disposed too many times and resulting in crashing the application. The Windows event viewer actually said that it disconnects the camera because of a driver error. Is this still a preferable way of handling events (creating them often and disposing them)?

So I'm not sure what to do. I've tried to define the CameraHandler in the MasterPage or an external class as a public variable in order to not dispose it all the time, but that didn't work out too well either. Now I don't create a new instance of the CameraHandler object, but events are getting fired multiple times since it adds the events every time the user reload that Photo.xaml page where the event handlers are defined...

I hope someone understands the issue and has some word of advise. :) This is not about a specific case, but more a general question about pages and events.

Edit: Here's the code for the "Photo.xaml": http://pastebin.com/XZBkLj4k

Try to move camera initialization to Page.Load event:

Page_Loaded(object sender, EventArgs e)
{
  if (CameraHandler != null)
  {
    CameraHandler = new SDKHandler();
    CameraHandler.LiveViewUpdated += new CameraHandler_LiveViewUpdated;
    CameraHandler.ProgressChanged += CameraHandler_ProgressChanged;
    CameraHandler.CameraHasShutdown += CameraHandler_CameraHasShutdown;
    CameraHandler.ImageSaveDirectory = Settings.TempLocation;
  }
}

and detactch from events in Page_Unloaded event:

Page_Unloaded(object sender, EventArgs e)
{
   if (!CameraHandler.IsFilming && CameraHandler.IsLiveViewOn)
   {
      CameraHandler.StopLiveView();
   }

   //maybe you were missing this
   if (CameraHandler.CameraSessionOpen) {
      CameraHandler.CloseSession();
   }

   CameraHandler.LiveViewUpdated -= CameraHandler_LiveViewUpdated;
   CameraHandler.ProgressChanged -= CameraHandler_ProgressChanged;
   CameraHandler.CameraHasShutdown -= CameraHandler_CameraHasShutdown;
   CameraHandler.Dispose();
   CameraHandler = null;
}

make sure Page_Unloaded is called (I don't see the xaml)

if it doesn't help, you should create and dispose CameraHandler in MainWindow and pass is trought property or constructor parameter to the page. however activation/deactivation of the camera keep in Photo page. In other words, handle CameraHandler as it was singleton.

Have you looked into using PRISM? This may help solve your problems.

Using the EventAggregator would allow you to publish / subscribe events based on a type; eg you declare the event like so:

public class ImageCapturedEvent : PubSubEvent<MyImageType>
{
}

subscribers can listen for images like so in a method you've defined:

_eventAggregator.GetEvent<ImageCapturedEvent >().Subscribe(OnImageCaptured);

public void OnImageCaptured(MyImageType image)
{
     //process image
}

then when the user takes an image, your code can publish it to all subscribers:

_eventAggregator.GetEvent<ImageCapturedEvent>().Publish(capturedImage);

PRISM also supports MEF or Unity so you can bootstrap your instances of the EventAggregator and your ImageHandler on load and make them available to the rest of the application.

Complete documentation is here .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM