views:

176

answers:

1

Hi All,

Long story short, I'm trying to write some toast-style popup notifications (similar to Growl) which should appear next to the system tray and stack as appropriate.

I can handle the instantiation/location/etc... but I want to add a capability for non-rectangular toasts. I'd also like to have Alpha transparency so a semi-transparent background PNG on the toast form would blend with the desktop or windows behind it.

So... To get the obvious out of the way:

Form.TransparencyKey is not sufficient for my needs as it's an all-or nothing transparency effect I want to get 50/50 foreground/background in some places, 0/100 in others, 100/0 in yet others etc.

My initial approach is to override the OnBackgroundPaint() method, comment out the call to MyBase.OnBackgroundPaint and use the graphics object in the eventargs to draw exactly what I want to a form.

This seems to work to start with - at the moment, I'm just drawing some rectangle for testing purposes so a PNG may present new difficulties but I haven't got there yet.

What I haven't been able to accomplish is updating the graphic - The first time the form is rendered, it shows perfectly as I'd expect (no border, just some rectangles floating on a desktop). If I move the windows behind the transparent window, the transparent window doesn't update/re-paint

I believe that I need to be calling Me.Invalidate() to force a re-draw but am unsure when I should make the call - How do I know a window behind me has changed its' contents?

Am I taking the wrong approach?

Many thanks

Edit: I tried putting a Me.Invalidate() inside a timer just to test how the redraw happens - it seems that it does trigger a re-draw but the re-draw opccurs OVER the existing form background - ie an area that was originally 50% opaque is now 75% opaque (50% + 50% of what was there before)

So, after a couple of Invalidate()s, my form is showing as a black box - I need to clear the background of the form before re-drawing but Graphics.Clear(Color) seems to simply do a fill with the specified color - and obviously for the purposes of this question, Colors.Transparent doesn't really mean transparent - It seems to be a trick used when rendering the window to "show contents of control beneath this" which just doesn't work when we're dealing with the form itself

In case anyone wants to replicate easily, the code for my form is below:

Imports System.Drawing
Public Class TransparentForm

    Private Timer As Timers.Timer

    Private Sub TransparentForm_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Timer = New Timers.Timer
        AddHandler Timer.Elapsed, AddressOf Timer_Tick
        Timer.Interval = 100
        Timer.Start()
    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal e As System.Windows.Forms.PaintEventArgs)
        ''MyBase.OnPaintBackground(e)
        Console.WriteLine("BackgroundPainted")
        For x = 0 To 9
            e.Graphics.FillRectangle(
                New SolidBrush(Color.FromArgb(CInt(x / 10 * 255), 127, 127, 127)),
                CInt(x * Me.Width / 10),
                0,
                CInt(Me.Width / 10),
                Me.Height
            )
        Next
    End Sub

    Sub Timer_Tick(ByVal sender As Object, ByVal e As EventArgs)
        Me.Invalidate()
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        Console.WriteLine("Painted")
    End Sub

    Protected Overrides Sub OnInvalidated(ByVal e As System.Windows.Forms.InvalidateEventArgs)
        MyBase.OnInvalidated(e)
        Console.WriteLine("Invalidated")
    End Sub

End Class
+1  A: 

There is one CodeProject article that shows how to use a png as the form's "skin". Obviously, this supports partial transparency instead of the 50/50 approach offered by Form.TransparencyKey.

This is the link to the codeproject article. I'm trying to upload the project in VB and will update this answer as soon as it is done.


EDIT

Here's the link to the VB.NET version of the CodeProject article I cited above.
http://www20.zippyshare.com/v/86701716/file.html

I'll try to review your code and see what can be done to help your situation.

Alex Essilfie
With regards to the article. You'll have to drop any 32-bit PNG image on the form to display the form with the image as the form's background. You'll have to override this process by specifying a PNG file in your code if you want to set the form's background to the image.
Alex Essilfie
Thanks - And I should be able to hack the implementation around a bit. I would appreciate it if you could identify the problem with my code - I'm off to have a look at your converted code. It may take me a few of hours to get back to you
Basiclife
Ok, interesting side-effect - Using the technique provided does indeed produce a fully alpha-transparency compatible form, however, no controls or other UI elements are rendered at all. In addition, no events are received for controls on the form. Do you have any suggestions?
Basiclife
I never actually used the code in any application so I didn't know of that no events side effect. I'll work on it when I break from work today and get back to you. Stay tuned.
Alex Essilfie
As a temporary workaround, I've modified the method to doa Control.DrawToBitmap(TheBackgroundBitmap) before the bitmap gets applied. This at least allows controls I explicitly call this on to be rendered - Obviously this still doesn't resolve the underlying issue...
Basiclife
@Basiclife: It appears drawing the controls to bitmap is the only workaround. I looked it up on the site and here's what I found [PerPixel Alpha Blend (Add Controls)](http://www.codeproject.com/Messages/2813052/Add-Controls.aspx).
Alex Essilfie
Thanks for getting back to me - It's not quite the solution I was hoping for but I agree it's the best I'm likely to find.
Basiclife