views:

112

answers:

1

I'm attempting to create a NotifyIcon that can be inherited so that I can add my own properties/etc. Through looking at a component class someone else wrote, I've made some progress as can be seen below, and the component can be dragged into the form. To be honest, I have little idea on what I'm doing, and there appears to be no tutorials anywhere on the internet that are of any use at all.

In the PrepareIcon method you see, the message box that pops up appears blank, even though I have tried changing the value from the designer default of notifyIconInheritable1. I have seen the NotifyIcon appear while in the designer, so I have been utterly confused on how this works.

The question is; what's wrong with this or what am I doing wrong, and am I wasting my time and shouldn't be attempting this at all?

namespace AwesomeNotifyIcon
{
    [DefaultProperty("Text"), DefaultEvent("Click"), Description("Displays an icon in the notification area, on the right side of the Windows taskbar, during run time")]
    public partial class NotifyIconInheritable : Component
    {
        private NotifyIcon notifyIcon;

        public NotifyIconInheritable()
        {
            //PrepareIcon();
            InitializeComponent();
        }

        public NotifyIconInheritable(IContainer container)
        {
            if (container != null)
            {
                container.Add(this);
            }
            PrepareIcon();
            InitializeComponent();
        }

        [Category("Appearance"), Description("The icon to associate with the balloon ToolTip."), DefaultValue(ToolTipIcon.None)]
        public ToolTipIcon BalloonTipIcon { get; set; }

        [Category("Appearance"), Description("The text to associate with the balloon ToolTip.")]
        public string BalloonTipText { get; set; }

        [Category("Appearance"), Description("The title of the balloon ToolTip.")]
        public string BalloonTipTitle { get; set; }

        [Category("Appearance"), Description("The icon to display in the system tray.")]
        public Icon Icon { get; set; }

        [Category("Appearance"), Description("The text that will be displayed when the mouse hovers over the icon.")]
        public string Text { get; set; }

        [Category("Behaviour"), Description("The shortcut menu to show when the user right-clicks the icon.")]
        public ContextMenuStrip ContextMenuStrip { get; set; }

        [Category("Behaviour"), Description("Determines whether the control is visible or hidden."), DefaultValue(false)]
        public bool Visible { get; set; }

        [Category("Data"), Description("User-defined data associated with the object.")]
        public object Tag { get; set; }

        [Category("Action"), Description("Occurs when the component is clicked.")]
        public event EventHandler Click;

        private void PrepareIcon()
        {
            notifyIcon = new NotifyIcon();
            notifyIcon.Dispose();
            MessageBox.Show(this.Text);

            if (Click != null)
                notifyIcon.Click += Click;
        }
    }
}

Here's the properties as seen in the designer:

http://cl.ly/1vIF/content

+2  A: 

When you add a control using the designer, it generates code that looks something like this:

NotifyIconInheritable icon = new NotifyIconInheritable();
icon.Text = "Some text";
parent.Controls.Add(icon);

You can see that your property isn't set until after the constructor has run. So, at the point when you call PrepareIcon, the Text really is null.

Other advice: as Henk says, you really shouldn't be calling Dispose() at this point in your code. You also shouldn't be showing a message box from a constructor, though hopefully that's just there for your testing purposes. Finally, because you're calling PrepareIcon from the constructor, .Click will always be null.

Dan Puzey
More importantly, any designer generated code is added to the component's `InitializeComponent` method. He should safely be able to call `PrepareIcon` after that method call.
Matthew Abbott
Moving `PrepareIcon()` to after `InitializeComponent()` didn't seem to change the output of the message box.
a2h
You're not thinking about the bigger picture. the `InitializeComponent` method is for the current component, setting any child control properties in the designer, the changes to those child controls will happen here. The instance of your `NotifyIconInheritable` is added to another control the next level up in your control tree, and its in that parent control's `InitializeComponent` method where the `Text` property is set.
Matthew Abbott
So in this instance, moving `PrepareIcon` after **this** control's `InitializeComponent` method is still getting it called before the property is set.What you may want to consider is moving the `PrepareIcon` call to somewhere later in the controls event lifecycle, possible before `OnPaint` or somewhere near?
Matthew Abbott
Does a component have an `OnPaint` event?
a2h
^ LOL, good point, no it doesn't. Er, he still needs to defer that method call possibly outside the initialisation code altogether, or possibly make his `NotifyIconInheritable` a `Control` that doesn't paint anything?
Matthew Abbott
I'm starting to think perhaps I should just create some extension methods and as for events just have some dodgy extension method like `notifyIcon.AddBlahEventCallback(notifyIcon_OnBlah)`
a2h
What exactly are you trying to do? It's unusual to wire up an eventhandler in the constructor in the way you are anyway - what behaviour are you looking for?
Dan Puzey