Question Click detection on a balloon tip is making me crazy

Strahan

Member
Joined
Mar 28, 2015
Messages
11
Programming Experience
3-5
Hi! I use OBS to keep a video log of meetings I am in. OBS saves as files like "2023-06-16 00:04:18.mkv". Every couple days, I have to go through and rename them to reflect what the meeting was about. It hit me today; I could leverage FileSystemWatcher to detect when videos are created then rename them immediately. In the most basic form, these are the classes:

C#:
public partial class Primary : Form {
  public Primary() {
    InitializeComponent();
  }

  private void Primary_Load(object sender, EventArgs e) {
    Notifications.Send("Video Monitor", "Video created!");
  }
}

public class Notifications {

  private static NotifyIcon notifyIcon;
  private static Timer disposeTimer;

  public static void Send(string title, string content) {
    if (notifyIcon == null) {
      notifyIcon = new NotifyIcon();
      notifyIcon.Icon = SystemIcons.Information;
      notifyIcon.Visible = true;
      notifyIcon.Click += (sender, e) => {
        MessageBox.Show("CLICK");
      };

      disposeTimer = new Timer();
      disposeTimer.Interval = 10000;
      disposeTimer.Tick += (s, e) => {
        if (notifyIcon != null) {
          notifyIcon.Visible = false;
          notifyIcon.Dispose();
          notifyIcon = null;
        }
        disposeTimer.Stop();
      };
      disposeTimer.Start();
    }

    notifyIcon.BalloonTipTitle = title;
    notifyIcon.BalloonTipText = content;
    notifyIcon.ShowBalloonTip(5000);
  }
}
When the program opens, I get my notification. I click the notification, nothing happens. I fired up a test project and copied the notifications class and called send, and it worked when I clicked the notification. It's making me crazy, I can't figure out why it works in my test program but not the other one. Any ideas?

Thanks!
 
Shouldn't you be handling the BalloonTipClicked event rather than the Click event? Click is raised when you click on the icon itself, but you say that you're clicking on the balloon notification.
 
*facepalm*

Thanks, it works!

Err kinda. I was tired of deleting/creating videos to test the notification, so I had done:
C#:
private void testToolStripMenuItem_Click(object sender, EventArgs e) {
  Notifications.Send("Notification Test", "This is the content of your notification.");
}
When the notification pops from that test being clicked in menu, I can click the balloon and get my CLICK messagebox. When I went to use the actual FSW version:
C#:
private void startMonitoringToolStripMenuItem_Click(object sender, EventArgs e) {
  /*systemActive = !systemActive;
  startMonitoringToolStripMenuItem.Text = (systemActive ? "&Stop" : "&Start") + " Monitoring";
  foreach (FileMatch match in cfg.FileMatches) FileEngine.Toggle(match, systemActive);*/
  FileSystemWatcher fsw = new FileSystemWatcher();
  fsw.Filter = "*.mkv";
  fsw.Path = @"D:\Misc\Videos";
  fsw.EnableRaisingEvents = true;
  fsw.Created += (nsender, ne) => {
    Notifications.Send("Video Monitor", "A video file has been saved!  Click here to name it.");
  };
  fsw.IncludeSubdirectories = true;
}
I had remarked the first three lines in case it was some weird thing because of having the FSW in the other class. So to make it simple, I put this FSW right in the UI class. When I create a file, I get the balloon popping up but when I click it, I do not get my CLICK messagebox.

So it works if I fire off the Notifications.Send through a user action or just as part of the program flow (like in my form Load event) but when it's fired from an FSW, it doesn't work. Any idea on that one?

EDIT: It just hit me, like a second after editing my post lol. I'm just a hobbyist so I don't know how it works "under the hood", but I was thinking what if when the send is fired from FSW it's not on the UI thread and maybe things not on UI won't pop? So I tried
C#:
    private void startMonitoringToolStripMenuItem_Click(object sender, EventArgs e) {
      /*systemActive = !systemActive;
      startMonitoringToolStripMenuItem.Text = (systemActive ? "&Stop" : "&Start") + " Monitoring";
      foreach (FileMatch match in cfg.FileMatches) FileEngine.Toggle(match, systemActive);*/
      FileSystemWatcher fsw = new FileSystemWatcher();
      fsw.Filter = "*.mkv";
      fsw.Path = @"D:\Misc\Videos";
      fsw.EnableRaisingEvents = true;
      fsw.Created += (nsender, ne) => {
        Invoke(new Action(delegate () {
          Notifications.Send("Video Monitor", "A video file has been saved!  Click here to name it.");
        }));      
      };
      fsw.IncludeSubdirectories = true;
    }
and sure enough, now I get "CLICK!" when I create my file! :)

I found that invoke snippet months ago when I was trying to figure out a problem with modifying controls from another thread. I thought maybe it would be of use here. Glad I wrote that down hehe.
 
Last edited:
The FileSystemWatcher raises its events on a thread pool thread by default. If you assign a form or control to the SynchronizingObject property, it will raise its events on the thread that owns that handle. If you're going to delegate to the UI thread in the event handler anyway, you may as well have the event raised on the UI thread in the first place.

It's also worth noting that your code as it is will create multiple FileSystemWatchers if that menu item is clicked multiple times. You should think about either disposing those instances or just using one and adding it in the designer.
 
Thanks for the tips. The real code doesn't create the FSW like that, I just used that as an example to simplify my post. I have a class FileMonitor that has an FSW instance and all the related config stuff for each provider, then a List<FileMonitor> in my main controller class. Normally, that click method toggles EnableRaisingEvents for each member of the collection.

Thanks though!
 

Latest posts

Back
Top Bottom