Click here to Skip to main content
15,885,659 members
Please Sign up or sign in to vote.
5.00/5 (2 votes)
See more:
Hello everyone.

First of all, sorry for my bad english.

Using:
Visual Studio 2005
Visual Basic.NET

I'm developing a small Media Player, an application which can play most popular music formats, and can view some image formats.

I have my custom control (called BtnEx) that inherits System.Windows.Forms.Control

I want to solve the next problem:
ArgumentException : Parameter is not valid

This error occurs in the next line of my code:
VB
Dim CImg as New Bitmap (PImg, e.ClipRectangle.Width - 2, e.ClipRectangle.Height - 2)

But only in Design Mode, not when I run my program (by pressing the F5 button).


When i build my project all works fine until I press my custom control (For dragging and selecting). Thats all happening in Design Mode (IDE)
A "X" image is appearing instead of Control's Image, and Visual Studio shows MessageBox with error description. In that description I can read in which line of code error occurs. (ArgumentException occured in file "C:\ ... \BtnEx.vb" line: 67.

When I Build my project (again) the red "X" image dissapears and all loks fine, but as I said, when i click on control that exception occurs.

I'm calling this procedure in OnPaint Sub.

This is the OnPaint Sub:

VB
Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
         MyBase.OnPaint(e)
            If PImg Is Nothing = False Then
            ' Error is in the next line:
                        Dim CImg As New Bitmap(PImg, e.ClipRectangle.Width - 2, e.ClipRectangle.Height - 2)
            ' When I run this program (F5) then no error is occured.
If Me.Enabled = True Then
                Select Case MS
                    Case EMouseState.MouseHover
                        ' HighLight The Image
                        IMGA.SetGamma(0.57#)
                        e.Graphics.DrawImage(CImg, CRect, 0, 0, CRect.Width, CRect.Height, GraphicsUnit.Pixel, IMGA)
                    Case EMouseState.MouseDown
                        ' Make Image darker
                        IMGA.SetGamma(1.77#)
                        e.Graphics.DrawImage(CImg, CRect, 0, 0, CRect.Width, CRect.Height, GraphicsUnit.Pixel, IMGA)
                    Case EMouseState.MouseUp
                        If InB = True Then ' If mouse is on it.
                            IMGA.SetGamma(0.57#)
                            e.Graphics.DrawImage(CImg, CRect, 0, 0, CRect.Width, CRect.Height, GraphicsUnit.Pixel, IMGA)
                        Else
                            e.Graphics.DrawImage(CImg, CRect)
                        End If
                    Case EMouseState.MouseLeave
                        e.Graphics.DrawImage(CImg, CRect)
                End Select
                Else
                    ' Method used by MicroSoft to paint controls disabled.
                    ControlPaint.DrawImageDisabled(e.Graphics, CImg, 1, 1, Color.Transparent)
            End If
        End If
    End Sub


When I use numbers instead e.ClipRectangle.Width or e.ClipRectangle.Height it runs fine.

Example :
VB
Dim InitWidth As Integer = 42
Dim InitHeight As Integer = 42
Dim CImg As New Bitmap (PImg, InitWidth, InitHeight)
' OR:
Dim CImg As New Bitmap (PImg, 42, 42)
' Then runs very well, without errors. Why ??

I have tested e.ClipRectangle.Width with MsgBox:
VB
MsgBox (e.ClipRectangle.Width.Tostring)
               'And MsgBox shows a correct value: 42


I know I can do this in other ways, but I want to know why is that happening ?
One of the other ways is to use Me.Width and Me.Height properties of control, but what when i want to use only part of control to draw on it ??


Example using Me.Width and Me.Height properties that works.
VB
Dim CImg As New Bitmap (PImg, Me.Width - 2, Me.Height - 2)


This is the whole Class
VB
Public Class BtnEx
    Inherits Control
    Private PImg As Image = Nothing
    Public Property Image() As Image
        Get
            Return PImg
        End Get
        Set(ByVal Value As Image)
            PImg = Value
            Me.Refresh()
        End Set
    End Property
    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        If PImg Is Nothing = False Then
            Dim CRect As New Rectangle(1, 1, e.ClipRectangle.Width - 2, e.ClipRectangle.Height - 2)
			' MsgBox("InitW : InitH = " + e.ClipRectangle.Width.ToString + " : " + e.ClipRectangle.Heigh.ToString)
            Dim IMGA As New Drawing.Imaging.ImageAttributes
			' ERROR : Parameter is not valid >
            Dim CImg As New Bitmap(PImg, e.ClipRectangle.Width - 2, e.CLipRectangle.Height - 2)
            ' I need to change size of the image (PImg) because user can choose an image that is bigger than by control.
            If Me.Enabled = True Then
                Select Case MS
                    Case EMouseState.MouseHover
                        ' HighLight The Image
                        IMGA.SetGamma(0.57#)
                        e.Graphics.DrawImage(CImg, CRect, 0, 0, CRect.Width, CRect.Height, GraphicsUnit.Pixel, IMGA)
                    Case EMouseState.MouseDown
                        ' Make Image darker
                        IMGA.SetGamma(1.77#)
                        e.Graphics.DrawImage(CImg, CRect, 0, 0, CRect.Width, CRect.Height, GraphicsUnit.Pixel, IMGA)
                    Case EMouseState.MouseUp
                        If InB = True Then ' If mouse is on it.
                            IMGA.SetGamma(0.57#)
                            e.Graphics.DrawImage(CImg, CRect, 0, 0, CRect.Width, CRect.Height, GraphicsUnit.Pixel, IMGA)
                        Else
                            e.Graphics.DrawImage(CImg, CRect)
                        End If
                    Case EMouseState.MouseLeave
                        e.Graphics.DrawImage(CImg, CRect)
                End Select
                Else
                    ' Method used by MicroSoft to paint controls disabled.
                    ControlPaint.DrawImageDisabled(e.Graphics, CImg, 1, 1, Color.Transparent)
            End If
        End If
    End Sub
    Protected Overrides Sub InitLayout()
        MyBase.InitLayout()
	Me.Refresh
    End Sub
    'Used to Refresh Control.
    Private Sub II()
        Me.Refresh()
    End Sub
    Dim InB As Boolean

    Private Enum EMouseState
        MouseUp = 0
        MouseHover = 1
        MouseDown = 2
        MouseLeave = 3
    End Enum
    Dim MS As EMouseState
    Protected Overrides Sub OnMouseEnter(ByVal e As System.EventArgs)
        InB = True
		MyBase.OnMouseEnter(e)
        MS = EMouseState.MouseHover
        II()
    End Sub
    Protected Overrides Sub OnMouseLeave(ByVal e As System.EventArgs)
        MyBase.OnMouseLeave(e)
        InB = False
        MS = EMouseState.MouseLeave
        II()
    End Sub
    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
        MyBase.OnMouseDown(e)
        If e.Button = Windows.Forms.MouseButtons.Left = True Then
            MS = EMouseState.MouseDown
            II()
        End If
    End Sub
    Protected Overrides Sub OnEnabledChanged(ByVal e As System.EventArgs)
        MyBase.OnEnabledChanged(e)
        Me.Refresh()
    End Sub
    Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
        MyBase.OnMouseUp(e)
        MS = EMouseState.MouseUp
        II()
    End Sub
    Public Sub New()
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint Or ControlStyles.OptimizedDoubleBuffer Or ControlStyles.ResizeRedraw Or ControlStyles.Selectable Or ControlStyles.SupportsTransparentBackColor Or ControlStyles.UserPaint Or ControlStyles.StandardClick, True)
        Me.DoubleBuffered = True
        MS = EMouseState.MouseLeave
        Me.Refresh()
    End Sub
End Class


And on the end, sorry for big question, and Thanks in Advance.

  
Posted
Updated 4-Jan-12 14:40pm
v2
Comments
Sergey Alexandrovich Kryukov 4-Jan-12 21:23pm    
Thanks for correctly formulated question -- a rare thing these days :-( I voted 5.
Hope my advice can help you.
--SA
XSON-NEON 5-Jan-12 10:52am    
Thanks for vote of 5.

Please do some sanity check of all of three parameters of the call: image (should be valid, not null), matching positive width and height. This is hard to do under debugger as Design mode is involved. To investigate the situation, you can use the class System.Diagnostics.EventLog, see http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlog.aspx[^].

You will get all the log information in the system log where you can examine it using the "Event Log" viewer, using "Eventvwr.msc".

Now, the possible resolution. Design-time can be a disaster, very hard to debug — don't overuse it. Check up the value of the property System.ComponentModel.Component.DesignMode and avoid any extensive or questionable processing if your control methods are executed when the DesignMode is true. Your design mode should only allow to render your control correctly with correct bounds and allow for editing of the properties using the PropertyGrid. All excessive event processing useful only in application execution mode (not design mode) should be avoided.

See http://msdn.microsoft.com/en-us/library/system.componentmodel.component.designmode.aspx[^].

—SA
 
Share this answer
 
@SAKryukov - Thank you for the quick reply. I appreciate it.

Quote:
Please do some sanity check of all of three parameters of the call: image (should be valid, not null), matching positive width and height.


I have checked the image in the code:
VB
If PImg Is Nothing = False

And I have also checked Height and Width with MsgBox:
VB
MsgBox ("Height is : " + e.ClipRectangle.Height.ToString)
' MsgBox returns the correct value : 42 in this case


But I have found a solution, of course, with your help.
You gave me an idea.

I put this code in the OnPaint Sub. It checks if the program is in Design Mode or not.

VB
' Using Control.DesignMode
If Me.DesignMode = True Then
' Do some stuff like : Draw image without using e.ClipRectangle, or something else
Else ' Running, draw images correctly
Dim CImg As New Bitmap (PImg, e.ClipRectangle.Width - 2, e.ClipRectangle.Height - 2)
' ... ... ...
End If


And it works without any error.
Your idea to using a Control.DesingMode is great.
This allow me to edit properies from the PropertyGrid

I voted 5 for your ansewr. Thanks a lot.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900