0

I have created a wpf application that has a button binded to an ICommand. When the button is clicked two TaskbarIcon objects are created along with two Toast Notification or BalloonTips as named by the Hardcodet.NotifyIcon.Wpf Nuget package I use by Philipp Sumi.

The ICommand code

public ICommand RunCalculationCommand_Approach2
{
    get { return new DelegateCommand<object>(ExecuteSqlAsync); }
}
private async void ExecuteSqlAsync(object obj)
{
    //1. TaskBar During Calculations (during calculations)
    Stream iconStream_one = Application.GetResourceStream(new Uri("pack://application:,,,/TestApp;component/Assets/loading.ico")).Stream;
    Stream iconStream_two = Application.GetResourceStream(new Uri("pack://application:,,,/TestApp;component/Assets/loading.ico")).Stream;

    TaskbarIcon tbi_during_calculations = new TaskbarIcon
    {
        Icon = new Icon(iconStream_one),
        LeftClickCommand = ShowWindowsCommand,
    };

    //2. TaskBar Calculations Status (calculations completed-failed-stopped)
    TaskbarIcon tbi_calculation_status = new TaskbarIcon
    {
        Icon = new Icon(iconStream_two),
        LeftClickCommand = ShowWindowsCommand,
    };

    try
    {
        //Notify the user that calculations have already started
        tbi_during_calculations.Visibility = Visibility.Visible;
        string title_startup = "Calculations Started";
        string text_startup = "You can now minimize the window and return back once the calculations finish.";
        tbi_during_calculations.ShowBalloonTip(title_startup, text_startup, BalloonIcon.None);

        DateTime timestamp_start = DateTime.Now;

        await Task.Run(() => RunCalculationsMethod(object_progressbar, "LOG_DETAILS", 1, true, getconnectionstring, CatchErrorExceptionMessage, this.CancellationTokenSource.Token), this.CancellationTokenSource.Token);
        
        string[] time_passed = DateTime.Now.Subtract(timestamp_start).ToString().Split(@":");

        //The code below is executed after the Task is completed or if it's cancelled.
        List<SucessfulCompletion> reportsucessfulcompletion = new List<SucessfulCompletion>();
        reportsucessfulcompletion = CheckLogsFailSuccessProcedure(SQLServerConnectionDetails());

        tbi_during_calculations.Icon.Dispose();
        tbi_during_calculations.Dispose();
        
        if (reportsucessfulcompletion[0].Result == 0)
        {
            //Add Balloon tip
            tbi_calculation_status.Visibility = Visibility.Visible;
            string title = "Calculations Completed";
            string text = $"Calculations have been completed in \n{time_passed[0]} hour(s), {time_passed[1]} minute(s) and {time_passed[2].Substring(0, 2)} seconds";
            tbi_calculation_status.ShowBalloonTip(title, text, BalloonIcon.None);
        }
        else
        {
            //Add Balloon tip
            tbi_calculation_status.Visibility = Visibility.Visible;
            string title = "Calculations Failed";
            string text = $"Calculations stopped \n{time_passed[0]} hour(s), {time_passed[1]} minute(s) and {time_passed[2].Substring(0, 2)} seconds ago";
            tbi_calculation_status.ShowBalloonTip(title, text, BalloonIcon.None);
        }
    }
    catch (Exception ex)
    {
        //..
    }
    finally
    {
        win_progressbar.Close();
        EnableRunCalculationsButton = true;
    }
}

As you will notice in the code snippet above I generate two TaskbarIcon objects:

  • tbi_during_calculations
  • tbi_calculation_status

The first is shown to the user during some awaiting Task.Run(() => RunCalculationsMethod(); as shown in my code above. During the calculation of the task, the user can click the TaskbarIcon and call this function ShowWindowsCommand. After the end of the calculations, the TaskbarIcon object tbi_during_calculations is disposed along with its Icon.

Then the second TaskBarIcon object tbi_calculation_status is generated, informing the user whether the calculations were successful or not. Depending on the calculations the BalloonTip would display a different message.

My problem is that when I have already click the application once I get what I want. A single TaskbarIcon. But if I re-click the button a second time without first closing the WPF Application, the TaskBarIcon object tbi_calculation_status is duplicated without overwriting the previous instance of it. As shown in the image below,

enter image description here

Do you know any smart way to get rid of the first TaskbarIcon object without closing the Application?

NikSp
  • 1,262
  • 2
  • 19
  • 42

1 Answers1

1

You have to hide (dispose) the tbi_calculation_status instance (the same as tbi_during_calculations)

The tbi_calculation_status icon is created for each button click so you will get two tbi_calculation_status icons on second button click (and three on third, etc.)

This is a little bit strange having two icons in the system tray for one application. You may use one icon but adjust tool tip when a calculation starts/stops.

oleksa
  • 3,688
  • 1
  • 29
  • 54
  • Thanks for the answer. Even though it's a valid answer, it's not an option I would like to select. This is because, if I dispose the second ```TaskbarIcon``` then the BalloonTip displayed automatically disappears after 5 secs. So in the notification displays for 5 secs and if the user was afk then he will never catch the notification. Is there any other alternative without using the ```.Dispose()``` option? – NikSp Jan 06 '21 at 16:05
  • @niksp There is another option. Try to create the `tbi_calculation_status` only once (when a form is shown) and dispose it when a form was closed. You may hide the `tbi_calculation_status` and show in the button click event – oleksa Jan 07 '21 at 17:12
  • Yeah ok that's an option. I wonder why WPF applications don't overwrite the presence of a TaskBarIcon if there is already one and instead a duplicate is created. – NikSp Jan 08 '21 at 18:40
  • The disposal of the ```tbi_calculation_status``` is already done at the end of the application exit (as it is supposed). But if the application remains open and the user clicks again the button "Run" the old taskbaricon remains open and also a new one is created. – NikSp Jan 08 '21 at 18:42
  • 1
    @NikSp try not to create `tbi_calculation_status` in the button click event handler. Create it when application starts if it is disposed on the application exit – oleksa Jan 11 '21 at 08:34
  • Ok I may try that and let you know about the outcome. Thanks for the suggestions. – NikSp Jan 11 '21 at 08:49