Windows.Forms.Panel 32767 size limit
I have an application that uses Windows.Forms.Panel
to display a list of pictures. When the height of the panel exceeds 32767 pixels the rest of the content is simply cut off.
example:
Windows.Forms.Panel myPanel;
ArrayList pictureList;
foreach(pic in pictureList) {
myPanel.Controls.Add(pic) // adds all the objects without complaints
}
In the example all elements are add to the panel without an error to be thrown, but after the panel has reached a size of 32767 no image is displayed anymore.
My question: Is it possible to break this limit and display more content in a panel?
I know that the approach is inconvinient in any way, but there is no time now to redesign the whole Application.
This is an architectural limitation in Windows. Various messages that indicate positions in a window, like WM_MOUSEMOVE, report the position in a 32-bit integer with 16-bits for the X and 16-bits for the Y-position. You therefore cannot create a window that's larger than short.MaxValue. This isn't exactly a real problem, nobody has a monitor that's wider than 32,767 pixels and won't for a long time to come.
You'll have to do this differently. Like using Graphics.TranslateTransform() in a Paint method.
LPARAM - A Data type of Windows used to pass message parameters to Windows Procedure. It is a 32 bit pointer which passes message as two parts i.e in High order(First 16 bits of 32 bits) and Low order(Second 16 bits of 32 bits).
Where
High order is used to pass the height of the control and
Low order is used to pass the width of the control
So if the height or width of the control exceeds 32762size, it shows error because
32767 is the highest number that can be represented in a signed 16bit integer.
Solution without a paint method
I had this exact problem. I didn't want to have to re-write functionality that was already coded into my child controls. This routine manages the child controls via a scrollbar, and keeps the out-of-play ones hidden and just offscreen.
Public Class ManuallyScrollingPanel
Inherits Panel
Public WithEvents sbar As New System.Windows.Forms.VScrollBar
Sub New()
MyBase.New()
Controls.Add(sbar)
sbar.Visible = True
Me.AutoScroll = False
End Sub
Sub SetScrollParams()
If PanelPositions.Any Then
Dim NewMax = CInt((From item In PanelPositions.Values Select item.Bottom).Max + 500) - Height
If sbar.Maximum <> NewMax Then
sbar.Maximum = NewMax
End If
End If
End Sub
Public Sub RegisterChildSize(pnl As Panel, DesiredBounds As Drawing.Rectangle)
PanelPositions(pnl) = DesiredBounds
SetScrollParams()
End Sub
Dim PanelPositions As New Dictionary(Of Panel, Drawing.Rectangle)
Private Sub ManuallyScrollingPanel_SizeChanged(sender As Object, e As EventArgs) Handles Me.SizeChanged
sbar.Top = 0
sbar.Left = Width - sbar.Width
sbar.Height = Me.Height
SetScrollParams()
sbar.LargeChange = CInt(Height * 0.9)
sbar.SmallChange = CInt(Height * 0.2)
End Sub
Private Sub sb_Scroll(sender As Object, e As ScrollEventArgs) Handles sbar.Scroll
ScrollTo(e.NewValue)
End Sub
Private Sub sb_ValueChanged(sender As Object, e As EventArgs) Handles sbar.ValueChanged
ScrollTo(sbar.Value)
End Sub
Sub ScrollTo(pos As Integer)
Me.AutoScroll = False
For Each kvp In PanelPositions
Dim VirtBounds = New Drawing.Rectangle(CInt(kvp.Value.Left), CInt(kvp.Value.Top - pos), CInt(kvp.Value.Width), CInt(kvp.Value.Height))
If VirtBounds.Bottom < 0 Or VirtBounds.Top > Height Then
' it's not visible - hide it and position offscreen
kvp.Key.Visible = False
kvp.Key.Top = VirtBounds.Top
Else
' Visible, position it
kvp.Key.Top = VirtBounds.Top
kvp.Key.Visible = True
End If
Next
End Sub
End Class
Then, for each child control (mine were dynamically added, sounds like the OP was doing the same thing) make this call:
CType(Parent, ManuallyScrollingPanel).RegisterChildSize(Me, PanelObject.Bounds)
Note I pass in the child's bounds separately as I build the controls from DTOs to allow the same app+views to render as a web app and a windows app. Same with limiting it to panels. Refactor out as needed.