【问题标题】:How to create a UserControl showing a balloon tip from a NotifyIcon repeated at a certain interval using a timer?如何创建一个 UserControl,显示来自 NotifyIcon 的气球提示,使用计时器以特定间隔重复?
【发布时间】:2020-09-18 11:07:00
【问题描述】:

我正在创建一个在用户定义的时间创建通知的应用程序。

基本上我用了两个WinForms:

  • 数字 1 用于获取通知数据并创建 NotificationObject 类的新实例,其中包含消息、标题、到期时间等通知数据。
  • Form 2 号用于跟踪通知。

当程序启动时,Form 编号 2 打开,并且有一个按钮可以打开Form 编号 1。当表单编号 1 关闭时,它将通知数据保存到 NotificationObject 类。 Form number 2 获得 NotificationObject,它是在关闭 Form number 1 时创建的,并将其添加到 ObservableCollection。当向ObservableCollection 添加某些内容时,它会创建一个带有构造函数参数DueTime、Title 和Message 的UserControl。然后在UserControl 中,我使用System.Threading.Timer 和NotifyIcon 创建通知。

即使我设置了 Callback 方法来创建 NotifyIcon 气球,它也没有显示任何内容。

表格编号 1

public partial class NotificationCreator : Form
{
    public NotificationObject ntfObj;
    
    public NotificationCreator()
    {
        InitializeComponent();
    }
    
    private void createNotification_Click(object sender, EventArgs e)
    {
        if (String.IsNullOrEmpty(timeInput.Text))
        {
            MessageBox.Show(
                "Please set the time.",
                "Time is not set",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error
            );
    
            return;
        }
    
        if (String.IsNullOrEmpty(titleInput.Text))
        {
            MessageBox.Show(
                "Please set the title.",
                "Title is not set",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error
            );
    
            return;
        }
    
        if (String.IsNullOrEmpty(messageInput.Text))
        {
            MessageBox.Show(
                "Please set the message.",
                "Message is not set",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error
            );
    
            return;
        }
    
        DateTime time = DateTime.Parse(timeInput.Text);
    
        DateTime dt = new DateTime(dateInput.Value.Year,
            dateInput.Value.Month,
            dateInput.Value.Day,
            time.Hour,
            time.Minute,
            0
        );
    
        ntfObj = new NotificationObject(dt, titleInput.Text, messageInput.Text);
    
        Close();
        Dispose();
    }
    
    private void timeInput_TextChanged(object sender, EventArgs e)
    {
        if (timeInput.Text.Length == 5)
        {
            try
            {
                DateTime dummy = DateTime.Parse(timeInput.Text);
    
                if (dummy.Hour <= DateTime.Now.Hour && dummy.Minute <= DateTime.Now.Minute && dummy.Hour != 00 && dummy.Minute != 00)
                {
                    MessageBox.Show("Please set the time for future",
                        "Invalid time",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Error);
    
                    return;
                }
    
                return;
            }
            catch
            {
                MessageBox.Show("Please set a valid time",
                    "Invalid time",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                return;
            }
        }
    }
    
    private void dateInput_ValueChanged(object sender, EventArgs e)
    {
        if (dateInput.Value < DateTime.Now.AddDays(-1))
        {
            MessageBox.Show("Please set the date for future.",
                "Invalid date",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);
    
                dateInput.Value = DateTime.Now;
                    
                return;
            }
        }
    }
}

表格编号 2

public partial class TrackingPanel : Form
{
    ObservableCollection<NotificationObject> ntfList = new ObservableCollection<NotificationObject>();

    public TrackingPanel()
    {
        InitializeComponent();

        ntfList.CollectionChanged += NtfList_CollectionChanged;
    }

    private void NtfList_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            NotificationObject ntfObj = e.NewItems[0] as NotificationObject;

            Notification ntf = new Notification(ntfObj.DueTime, ntfObj.ntfTitle, ntfObj.ntfMessage);

            ntfPanel.Controls.Add(ntf);
        }
    }

    private void TrackingPanel_Load(object sender, EventArgs e)
    {}

    private void TrackingPanel_Resize(object sender, EventArgs e)
    {
        if (WindowState == FormWindowState.Minimized)
        {}
    }

    private void createNotification_Click(object sender, EventArgs e)
    {
        NotificationCreator Tool = new NotificationCreator();
        Tool.ShowDialog();

        ntfList.Add(Tool.ntfObj);
    }
}

通知对象

/// <summary>
/// An object that represents the Notification and contains Notification information.
/// </summary>
public class NotificationObject
{
    /// <summary>
    /// Notification due time.
    /// </summary>
    public DateTime DueTime { get; set; }
    /// <summary>
    /// Title of Notification.
    /// </summary>
    public string ntfTitle { get; set; }
    /// <summary>
    /// Notification Message.
    /// </summary>
    public string ntfMessage{ get; set; }

    public NotificationObject(DateTime dueTime, string title, string message)
    {
        DueTime = dueTime;
        ntfTitle = title;
        ntfMessage = message;
    }
}

用户控制

 public partial class Notification : UserControl
    {
        private readonly System.Threading.Timer timer;

        public Notification(DateTime dt, string Title, string Message)
        {
            InitializeComponent();

            this.Title.Text = Title;
            this.Message.Text = Message;

            ntfIco.Visible = false;

            timer = new System.Threading.Timer(NotificationOccurs, null, dt - DateTime.Now, TimeSpan.FromSeconds(20));
        }

        private void NotificationOccurs(object state)
        {
            ntfIco.Visible = true;

            ntfIco.ShowBalloonTip(3500, Title.Text, Message.Text, ToolTipIcon.Info);

            ntfIco.Visible = false;
        }

        private void Notification_Load(object sender, EventArgs e)
        {
            ntfPic.Image = Properties.Resources.Search_Png;
        }
    }

编辑

我在 UserControl 中使用了 System.Windows.Forms.Timer 还是不行。

public partial class Notification : UserControl
    {
        public Notification(DateTime dt, string Title, string Message)
        {
            InitializeComponent();

            this.Title.Text = Title;
            this.Message.Text = Message;

            ntfIco.Visible = false;

            Timer.Interval = (int)(dt - DateTime.Now).TotalMilliseconds;

            Timer.Start();
            
        }

        private void Notification_Load(object sender, EventArgs e)
        {
            ntfPic.Image = Properties.Resources.Search_Png;
        }

        private void Timer_Tick(object sender, EventArgs e)
        {
            ntfIco.Visible = true;

            ntfIco.ShowBalloonTip(3500, Title.Text, Message.Text, ToolTipIcon.Info);

            Timer.Interval = 10 * 1000;

            ntfIco.Visible = false;
        }
    }

【问题讨论】:

  • 使用 System.Windows.Forms.Timer ,System.Threading.Timer 的回调不会在 UI 线程上自动执行。
  • 否则修改控件时需要与UI线程同步。或许问题就出在于此。
  • @OlivierRogier 没错,但是如果有专门为此设计的计时器,为什么还要麻烦呢?
  • 使用与 UI 兼容的 winforms 计时器。
  • 一个表单有一个实例。当您使用“新”时,它会创建实例。然后使用 Show 或 ShowDialog 显示表单。 ShbowDialog 的焦点一直停留在表单上,​​直到关闭。窗体打开时焦点可以移动的 Show 方法。关闭表单将释放表单的实例,并且任何计时器也将被释放。您可以通过捕获关闭事件来退出表单而不进行处理。有关示例代码,请参阅我的两个表单项目:stackoverflow.com/questions/34975508/…

标签: c# winforms timer user-controls notifyicon


【解决方案1】:

来自 cmets 的讨论:

  • 一定要设置通知图标的 Icon 属性。

  • 保持 WinForms 计时器与 UI 线程正常运行。

  • 不要在气球提示弹出后将通知图标设置为 false,否则它会关闭。

  • 让气球尖端自行褪色。

  • 如果您想隐藏通知图标,请在 BallonTipClosed 事件中执行此操作。

private void Timer_Tick(object sender, EventArgs e)
{
  ntfIco.Visible = true;
  ntfIco.ShowBalloonTip(3500, Title.Text, Message.Text, ToolTipIcon.Info);
  Timer.Interval = 10 * 1000;
}
public Notification(DateTime dt, string Title, string Message)
{
  InitializeComponent();
  this.Title.Text = Title;
  this.Message.Text = Message;
  ntfIco.Visible = false;

  ntfIco.BalloonTipClosed += (sender, e) => ntfIco.Visible = false;

  Timer.Interval = (int)( dt - DateTime.Now ).TotalMilliseconds;
  Timer.Start();
}

【讨论】:

  • Olivier 先生感谢您抽出宝贵时间回答我的问题。现在可以了。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多