9

I'm going to show a error message in my program .

I'd like my messages to be like image below,

enter image description here

as you can see, I need a dark shadow to be shown when message pops up .

I follow two solution to do this :

1 - I take a screenshot of program (and I mix it with a black color, to be bit a dark) and then I attach it to a panel and I show the panel and then message form pops up . it doesn't work because sometimes it takes screenshot from other programs that is on the screen (for example telegram notifications)

2 - I use a rich panel (that I got from internet) that it can have opacity property, and then I set panel's color to black and opacity to 0.5. then I pop up the message. it doesn't work because this new panel does not cover all elements (IDK why !)

enter image description here

both of this solutions had some problems and did not work . Is there any solution to show such this messages ?

im using win forms not WPF

this my riched panel :

public class ExtendedPanel : Panel
{
    private const int WS_EX_TRANSPARENT = 0x20;
    public ExtendedPanel()
    {
        SetStyle(ControlStyles.Opaque, true);
    }

    private int opacity = 50;
    [DefaultValue(50)]
    public int Opacity
    {
        get
        {
            return this.opacity;
        }
        set
        {
            if (value < 0 || value > 100)
                throw new ArgumentException("value must be between 0 and 100");
            this.opacity = value;
        }
    }
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.ExStyle = cp.ExStyle | WS_EX_TRANSPARENT;
            return cp;
        }
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        using (var brush = new SolidBrush(Color.FromArgb(this.opacity * 255 / 100, this.BackColor)))
        {
            e.Graphics.FillRectangle(brush, this.ClientRectangle);
        }
        base.OnPaint(e);
    }
}

this is how i use it :

using (ExtendedPanel p = new ExtendedPanel())
{
  p.Location = new Point(0, 0);
  p.Size = f.ClientRectangle.Size;
  p.BackgroundImage = bmp;
  e.f.Controls.Add(p);
  //e.p = p;
  p.BringToFront();
  e.StartPosition = FormStartPosition.CenterParent;
  e.lblTitr.Text = header;
  e.lblText.Text = text;
  e.ShowDialog(f);
  // p.Visible = false;
  // e.f.Controls.Remove(p);
  e.f.Controls.Remove(p);
  e.f.Refresh();

}

LarsTech
  • 80,625
  • 14
  • 153
  • 225
Amir Khademi
  • 273
  • 1
  • 6
  • 13
  • what u mean "new panel does not cover all elements"? not reaching edges of parent or its not on top of some controls? – Alfarem Jan 22 '16 at 13:17
  • MahApps.Metro does implement a Dialog mostly likely to yours: [MahApps.Metro/Dialog](http://mahapps.com/controls/dialogs.html) – Michael Mairegger Jan 22 '16 at 13:20
  • Never did such, but you might be interested in this: http://stackoverflow.com/questions/4013622/adjust-screen-brightness-using-c-sharp – Ian Jan 22 '16 at 13:20
  • Do you use `WPF` or `WinForms` ? Your second solution is OK for winforms but you should set minimal Z-Order for your shadow rich panel by command `RichPanel.BringToFront();` and then show your dialog. – Ilia Maskov Jan 22 '16 at 13:31
  • do you have the option to change the zOrder on the panel. something like YourPanel.BringToFront()? then open your messagebox – Charles May Jan 22 '16 at 13:31
  • 1
    Also [this other SO topic](http://stackoverflow.com/questions/27304874/creating-a-dark-background-when-a-new-form-appears) might help. It seems to do what you are doing but maybe there is something helpful in the code. – Charles May Jan 22 '16 at 13:43
  • i used BringToFront already , the problem seemed to be more than this – Amir Khademi Jan 22 '16 at 19:03
  • See [Draw semi transparent overlay image all over the windows form having some controls](http://stackoverflow.com/q/4503210/719186) – LarsTech Jan 22 '16 at 19:35
  • [http://stackoverflow.com/a/4464161/1565525](http://stackoverflow.com/a/4464161/1565525) – Fabio Jan 22 '16 at 19:38
  • You need to "print" the client area of the form in a bitmap then apply the filtering/effects (dim) to the bitmap, put a control in front off everything else that takes all the space of the form and override it's print method to display the bitmap as if it was its own background. Check my answer as it has the demo project attached. – Mihail Shishkov Jan 22 '16 at 20:48
  • Have you resolved your problems? – TaW Jan 26 '16 at 18:08

2 Answers2

3

You can use two Forms to achieve the effect:

enter image description here

private void button_Click(object sender, EventArgs e)
{
    Enabled = false;
    Form shadow = new Form();
    shadow.MinimizeBox = false;
    shadow.MaximizeBox = false;
    shadow.ControlBox = false;

    shadow.Text = "";
    shadow.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
    shadow.Size = Size;
    shadow.BackColor = Color.Black;
    shadow.Opacity = 0.3;
    shadow.Show();
    shadow.Location = Location;
    shadow.Enabled = false;

    // here you should use your own messageBox class!
    Form msg = new Form();
    Button btn = new Button() { Text = "OK"};
    btn.Click += (ss, ee) => { msg.Close(); };
    msg.Controls.Add(btn);
    msg.FormClosed += (ss, ee) => { shadow.Close(); Enabled = true; };

    msg.Size = new System.Drawing.Size(200, 100);
    msg.StartPosition = FormStartPosition.Manual;
    msg.Location = new Point(shadow.Left + (shadow.Width - msg.Width) / 2, 
                             shadow.Top + (shadow.Height - msg.Height) / 2);
    msg.ShowDialog();
}

Most of the things I do to msg should go into your own custom messagebox form class, of course..

One problem is that the shadow form shows in the task bar, but you can set ShowInTaskbar to false..

TaW
  • 53,122
  • 8
  • 69
  • 111
  • it is ok , but why when i close it , it minimised and i have to click on its icon in task bar and show it again? – Amir Khademi Feb 04 '16 at 19:14
  • I don't know why, it doesn't here, neither when closing the x nor when clicking the button. You could try to code the closing event if you don't find out what is causing it, but finding causes is better than finding workarounds.. – TaW Feb 04 '16 at 19:22
  • thank you alot , but what is your advice for minimising? can i some how maximaise my main form again after minimising? or it is possible to lock the form from minimising before showing the dialog? – Amir Khademi Feb 04 '16 at 19:36
  • Hm, in my code I start with `Enabled = false;` so minimizing the main form is not even possible as I thought it shouldn't as the dialog is meant to be modal, no? Adding a `WindowState = FormWindowState.Maximized` or `Normal` to the `{ shadow.Close(); Enabled = true; }` block may help you. – TaW Feb 04 '16 at 19:41
  • nice solution! Thank you – Jevgenij Kononov Jan 02 '18 at 12:01
  • I have notice one problem. When you press in taskbar your application your dialog disappears. So you actively need to press to another application to bring back your msg dialog. – Jevgenij Kononov Jan 02 '18 at 12:25
0

This is not a trivial task. The best way to do it is to create your own custom control. You can use the attached project as a basis although it is doing the job it would be much better if it inherits from Control and not UserControl directly :)

Download Project

You'll need 7zip to decompress it.

Good luck

Mihail Shishkov
  • 14,129
  • 7
  • 48
  • 59