2

I am trying to create a taskbar replacement, and I want a button for each running application.

public void AddBtn(string name) {
        Button newButton = new Button();
        this.Controls.Add(newButton);
        newButton.Location = new Point(count * 75, Screen.PrimaryScreen.Bounds.Height - 25);
        newButton.Text = name;
        newButton.Name = count.ToString();
        newButton.BringToFront();
        count++;
    }

    private void GetRunning()
    {
        Process[] processes = Process.GetProcesses();
        foreach (Process process in Process.GetProcesses().Where(p => !string.IsNullOrEmpty(p.MainWindowTitle)).ToList())
            AddBtn(process.ProcessName);
    }

This is what I have so far, it creates a button for each running application. I need to detect if one of the applications close, so I can remove the button that corresponds with it. If you think there is a better way to do it, let me know.

1
  • Sidenote: There are more specific rules deciding whether a window appears on the taskbar or not (your current solution would, for example, even list those typical WinForms windows which have ShowInTaskbar set to false). S. web.archive.org/web/20110123054624/http://msdn.microsoft.com/… Commented Aug 6, 2017 at 21:41

1 Answer 1

7

First off, it would be best to move the code for adding the buttons elsewhere, and only use GetRunning to get the currently running processes. Modify it like so:

private List<Process> GetRunning()
{
    return Process.GetProcesses().Where(p => !string.IsNullOrEmpty(p.MainWindowTitle)).ToList();
}

private void AddButtons()
{
    for (var process in this.GetRunning())
    {
        AddBtn(process.ProcessName);
    }
}

Now, regarding your issue, there are two solutions:

Solution 1: Use events

Create a method, HandleClosed, which handles all the operations that need to be done when a process has exited:

private void HandleClosed(Process sender, EventArgs e)
{
    // Stuff
}

Then, you can bind it to the processes' Exited event like so:

private void BindProcesses()
{
    foreach (var process in this.GetRunning())
    {
        process.EnableRaisingEvents = true;
        process.Exited += this.HandleClosed;
    }
}

Now, whenever one of the processes exits, HandleClosed will be called, and the process that closed will be passed to it via sender.

Solution 2: Managing it yourself

Add a private field to your class, private List<Process> prevProcesses;.

Then create a new method, GetClosed:

private List<Process> GetClosed()
{
    var current = GetRunning();
    var result = this.prevProcesses.Except(current);
    this.prevProcesses = current;
    return result.ToList();
}

What this method does is it gets the current running processes, then compares that enumeration to prevProcesses. The processes that are in prevProcesses but aren't in current are the ones that have closed. Then, it updates prevProcesses with the current enumeration.

Finally, get the initial value for prevProcesses in your constructor, or any other method that you use for initialization:

this.prevProcesses = this.GetRunning();

Sign up to request clarification or add additional context in comments.

1 Comment

For solution 1, don't you need to add process.EnableRaisingEvents = true; to make it work?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.