views:

67

answers:

1

Hi,

I have one Windows Form with

this.BackColor = Color.Red

and

this.TransparencyKey = Color.Red

and there is one PictureBox (png image with transparency corners) on this form,

PictureBox.SizeMode = Normal.

Then I set SizeMode of PictureBox to StretchImage and get other result:
you can see it here

(sorry, I can put one hyperlink only)

You can see red points/dots, but it is not Color.Red because it is transparency key of form.

I tried to implement transparent form, transparent control to remove these "red" points. Anyways, I would like to ask about my last point - I tried to override "OnPaintBackground" method and when I implemented some like code below:

e.Graphics.FillRectangle(Brushes.Red, ClientRectangle);
TextureBrush brush = ImageHelper.ScaleImage(BackgroundImage, ClientRectangle.Width, ClientRectangle.Height);
e.Graphics.FillRectangle(brush, ClientRectangle);

I saved scaled BitMap to file before putting it to TextureBrush - this png scaled image doesn't contain "red" points, but they were painted on form.

Does somebody have any idea why it happens and tell me some way to solve it.

Best regards.

+1  A: 

This happens because GDI+, which is drawing the image, doesn't know that red is becoming transparent.

Therefore, it blends the borders of the image with the red background, creating reddish (but not completely red) pixels which do not become transparent.

To solve this, you'll need to make a layered window.

EDIT:

Use the following native methods:

static class NativeMethods {
    public const int LayeredWindow = 0x80000;//WS_EX_LAYERED

    #region Drawing
    [DllImport("User32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool UpdateLayeredWindow(IntPtr handle, IntPtr screenDc, ref Point windowLocation, ref Size windowSize, IntPtr imageDc, ref Point dcLocation, int colorKey, ref BlendFunction blendInfo, UlwType type);

    [DllImport("gdi32.dll")]
    public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

    [DllImport("User32.dll")]
    public static extern IntPtr GetDC(IntPtr hWnd);

    [DllImport("User32.dll")]
    public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);

    [DllImport("gdi32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeleteDC(IntPtr hdc);

    [DllImport("gdi32.dll")]
    public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);

    [DllImport("gdi32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool DeleteObject(IntPtr hObject);
    #endregion
}
struct BlendFunction {
    public byte BlendOp;
    public byte BlendFlags;
    public byte SourceConstantAlpha;
    public byte AlphaFormat;
}
enum UlwType : int {
    None = 0,
    ColorKey = 0x00000001,
    Alpha = 0x00000002,
    Opaque = 0x00000004
}

Override the form's CreateParams:

protected override CreateParams CreateParams {
    get {
        CreateParams createParams = base.CreateParams;
        createParams.ExStyle |= NativeMethods.LayeredWindow;
        return createParams;
    }
}

Call the following function in OnShown:

static Point Zero;
[SuppressMessage("Microsoft.Usage", "CA1806:DoNotIgnoreMethodResults")]
void UpdateWindow() {
    IntPtr screenDC = NativeMethods.GetDC(IntPtr.Zero);
    IntPtr imageDC = NativeMethods.CreateCompatibleDC(screenDC);
    IntPtr gdiBitmap = IntPtr.Zero;
    IntPtr oldBitmap = IntPtr.Zero;

    try {
        gdiBitmap = image.GetHbitmap(Color.FromArgb(0));                //Get a GDI handle to the image.
        oldBitmap = NativeMethods.SelectObject(imageDC, gdiBitmap);     //Select the image into the DC, and cache the old bitmap.

        Size size = image.Size;                                         //Get the size and location of the form, as integers.
        Point location = this.Location;

        BlendFunction alphaInfo = new BlendFunction { SourceConstantAlpha = 255, AlphaFormat = 1 }; //This struct provides information about the opacity of the form.

        NativeMethods.UpdateLayeredWindow(Handle, screenDC, ref location, ref size, imageDC, ref Zero, 0, ref alphaInfo, UlwType.Alpha);
    } finally {
        NativeMethods.ReleaseDC(IntPtr.Zero, screenDC);                 //Release the Screen's DC.

        if (gdiBitmap != IntPtr.Zero) {                                 //If we got a GDI bitmap,
            NativeMethods.SelectObject(imageDC, oldBitmap);             //Select the old bitmap into the DC
            NativeMethods.DeleteObject(gdiBitmap);                      //Delete the GDI bitmap,
        }
        NativeMethods.DeleteDC(imageDC);                                //And delete the DC.
    }
    Invalidate();
}
SLaks
The TransparencyKey property already uses layered windows to achieve its effect.
Hans Passant
Yes, but it doesn't do it the way he needs to. He needs to give a transparent image to use as the window background.
SLaks
This solution doesn't work (as I need :) ).I created new project, added your code above, inserted background image (it has transparent corners) with stretch layout, set background color and transparency key as red colour - and saw the same red dots...
Maxim Polishchuk
Do not set TransparencyKey.
SLaks
Ahaa... you described solution of transparent windows - http://blogs.msdn.com/mswanson/archive/2005/07/07/436618.aspx
Maxim Polishchuk
It works, thank you!!!One question: what I need do in order to see windows controls which I added to form before, because form shows background image only.
Maxim Polishchuk
You can put your controls on a second form with a transparent background and put the second over the layered one. (And handle the `Move` event to keep them together).
SLaks
Is it possible to use one form? By example: use form with a transparent background and put on it two panels - panel with controls and panel with background image. Another words: is it possible to implement some panel with background image instead of form... or solution above is for forms only?
Maxim Polishchuk
I don't know; try it or Google it. Controls cannot be layered windows; this code only works for forms.
SLaks
http://www.codeproject.com/KB/miscctrl/AlphaForm.aspx?msg=2380283
SLaks
Window form cannot create handle during openning if its panel overrides CreateParams property to add layered extended style... :(
Maxim Polishchuk
Very nice article, thank you very much :)
Maxim Polishchuk