Neal Darley
Neal Darley

Reputation: 13

Programmatically created form is blank

I'm trying to create a pop up to notify users of a successful action. It is supposed to be visible for a couple seconds and fade away on its own. To do this, I've created a form that inherits from Form and sets the ShowWithoutActivation property to true, as well as a static class to control its construction and manipulate its opacity.

The problem is that when the new form is created, it has the correct size and initial opacity, but is completely blank. The only child control, a docked (Fill) label does not show. The Background/Foreground Color properties I set in the designer seem to be ignored in favor of default values as well. The Form fades and closes as intended.

The form itself:

public partial class TempForm : Form
{
    protected override bool ShowWithoutActivation
    {
        get { return true; }
    }

    public TempForm(string message)
    {
        InitializeComponent();
        messageLabel.Text = message;
    }

    private TempForm() { }

}

The static class that creates it:

public static class FadeAwayNotifier
{

    public static void DisplayFadeNotification(Point parentLocation, string message)
    {
        Task t = Task.Factory.StartNew(() =>
        {
            int fadeDelay = 2000;
            int animationLength = 1000;
            int threadRestLength = 20;

            Form popUp = buildForm(parentLocation, message);
            popUp.Show();

            int opacityIncrements = (animationLength / threadRestLength);
            double opacityDecrementAmount = popUp.Opacity / opacityIncrements;

            Thread.Sleep(fadeDelay);

            for (int i = 0; i < opacityIncrements; i++)
            {
                Thread.Sleep(threadRestLength);
                popUp.Opacity -= opacityDecrementAmount;
            }

            popUp.Close();
        });

    }

    private static Form buildForm(Point startLocation, string text)
    {
        TempForm returnForm = new TempForm(text);

        returnForm.Location = startLocation;
        returnForm.messageLabel.Text = text;
        returnForm.BackColor = Color.Black;
        returnForm.ForeColor = Color.White;

        return returnForm;
    }

}

And, if it's helpful, here is the designer code for TempForm:

/// <summary>
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary>
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    #region Windows Form Designer generated code

    /// <summary>
    /// Required method for Designer support - do not modify
    /// the contents of this method with the code editor.
    /// </summary>
    private void InitializeComponent()
    {
        this.messageLabel = new System.Windows.Forms.Label();
        this.SuspendLayout();
        // 
        // messageLabel
        // 
        this.messageLabel.BackColor = System.Drawing.Color.Black;
        this.messageLabel.Dock = System.Windows.Forms.DockStyle.Fill;
        this.messageLabel.Font = new System.Drawing.Font("Cambria", 14.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
        this.messageLabel.ForeColor = System.Drawing.Color.White;
        this.messageLabel.Location = new System.Drawing.Point(0, 0);
        this.messageLabel.Name = "messageLabel";
        this.messageLabel.Size = new System.Drawing.Size(254, 81);
        this.messageLabel.TabIndex = 0;
        this.messageLabel.Text = "Message";
        this.messageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
        // 
        // TempForm
        // 
        this.AutoScaleDimensions = new System.Drawing.SizeF(9F, 19F);
        this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
        this.BackColor = System.Drawing.Color.Black;
        this.ClientSize = new System.Drawing.Size(254, 81);
        this.Controls.Add(this.messageLabel);
        this.Font = new System.Drawing.Font("Cambria", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
        this.ForeColor = System.Drawing.Color.White;
        this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
        this.Margin = new System.Windows.Forms.Padding(4, 4, 4, 4);
        this.Name = "TempForm";
        this.Opacity = 0.8D;
        this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
        this.Text = "tempForm";
        this.TopMost = true;
        this.ResumeLayout(false);

    }

    #endregion

    public System.Windows.Forms.Label messageLabel;

For those asking how the method is being called:

private void btnUpdate_Click(object sender, EventArgs e)
    {
        Cursor.Current = Cursors.WaitCursor;

        /* Input validation here */

        if (cmbBox.SelectedValue != null)
        {
             updateMethod(a, b....out errorMessage);

            if (String.IsNullOrEmpty(errorMessage))
                       FadeAwayNotifier.DisplayFadeNotification(this.Location, "Rule successfully updated");

        }
        else
            MessageBox.Show("A selection must be made in order to update");

        Cursor.Current = Cursors.Default;
    }

I've searched around but haven't seen anything that seemed to relate to the situation. I'm happy to be corrected if I missed something, though.

Why is the form that's created completely blank?

Upvotes: 1

Views: 104

Answers (1)

Aleksa Ristic
Aleksa Ristic

Reputation: 2499

Your form is blank because you are trying to show it inside Task.Factory.StartNew().

Task.Factory.StartNew() runs code inside it asynchronous which is for some reason problem for form.Show() method.

Solution for this is to instead of Task t = Task.Factory.StartNew(... use Task t = new Tast(.... and then after you created task you run it with t.RunSynchronously(). This way it will work.

How i am displaying temp forms is:

Create temporary form create new blank winform (through vs solution explorer)

Add code like this:

public partial class TempForm : Form
{
    System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
    double seconds = 3;

    public TempForm(int secs, string text)
    {
        InitializeComponent();

        //Custom property to dock it to down right to the screen
        Rectangle workingArea = Screen.GetWorkingArea(this);
        this.Location = new Point(workingArea.Right - Size.Width, workingArea.Bottom - Size.Height);

        t = new System.Windows.Forms.Timer();
        this.seconds = (secs != 0) ? secs : this.seconds;
        richTextBox1.Text = text;
    }

    private void TempForm_Load(object sender, EventArgs e)
    {
        t.Interval = (int)(seconds * 1000);
        t.Tick += new EventHandler(CloseForm);
        t.Start();
    }

    private void CloseForm(object sender, EventArgs e)
    {
        this.Close();
        this.Dispose();
    }

    public static void Show(int seconds, string text)
    {
        TempForm tf = new TempForm(seconds, text);
        tf.Show();
    }
}

To call it just use TempForm.Show(10, "SomeText");

Also make it look better (not like standard form) so it looks like this:

enter image description here

Upvotes: 1

Related Questions