0

This is more a design than a programming question (well, maybe not). I have 4 CheckedListBoxes which are filled with Data from an SQLite-database (Visual Studio 2010), and some of the entries exceed the width of the Box. I know that I can include a horizontal scrollbar in a CheckedListBox but everybody hates horizontal scrollbars (very ugly), so I tried to find an option to automatically wrap the text that doesn't fit. So if there is any solution to have the text wrapped when the width of the box is too small it would be awesome.

I could extend the window size but it is already over 1000px in width and some of the users use computers made of wood with 1024x768 solution, so that's not really an option.

Datagrid would be another option but I thought there must be an easier solution. Any hints?

Edit: Sorry, it's Windows Forms.

Broco
  • 217
  • 2
  • 18
  • Webforms, MVC, or Windows Form application? – Kaizen Programmer Jun 26 '14 at 21:57
  • My first thought was OwnerDraw, but apparently [it's not an easy path](http://stackoverflow.com/questions/18725111/can-i-use-a-drawitem-event-handler-with-a-checkedlistbox), though http://www.devexpress.com/Support/Center/Question/Details/Q267668 suggests that it might not be so bad. – ClickRick Jun 26 '14 at 21:58
  • @Michael_B Sorry, it's Windows Form application. – Broco Jun 26 '14 at 22:20

1 Answers1

1

You can write your own CheckedListBox pretty easily using a panel with some actual CheckBoxes on it so you can do the other things you'd expect such as disable certain ones, fix the way it cuts off drop characters, iterate them and so forth.

The problem with wrap, is a) determining the Text Extent of long text so you know how tall to make each checkbox, and b) having to keep a cumulative items height so you know where to add the next one. Of course, once you support wrap, you have to be able to adjust them all which involves moving them when a text change causes one in the middle to grow/shrink.

The panel's AutoScroll handles all the scrolling for you, which includes adding a HSCroll as needed, which is not always desirable. One way to overcome this, which might work for the actual CheckedListBox you are using, is to eat the HScroll instead.

<DllImport("user32.dll")> _
Private Shared Function ShowScrollBar(hWnd As IntPtr, 
              wBar As Integer, 
              bShow As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean

End Function

Then in form load or perhaps after you have populated it:

ShowScrollBar(myControl.Handle, ScrollBarDirection.SB_HORZ, False)

You can also just subclass the existing CheckedListBox to eat the scrollbar in OnClientSizeChanged

Public Class CheckedListBox2
    Inherits CheckedListBox

    ' optionally remove the scroll bar
    Public Property VerticalScrollOnly As Boolean

    ' PInvokes
    <DllImport("user32.dll", SetLastError:=True)>
    Public Shared Function GetWindowLong(ByVal hWnd As IntPtr, 
                           ByVal nIndex As Integer) As Integer
    End Function

    <DllImport("user32.dll")>
    Private Shared Function ShowScrollBar(hWnd As IntPtr, 
                                         wBar As Integer, 
                                        bShow As Boolean) _ 
                             As <MarshalAs(UnmanagedType.Bool)> Boolean
    End Function

    '// window style constants for scrollbars
    Private Const WS_VSCROLL As Integer = &H200000
    Private  Const WS_HSCROLL As Integer = &H100000
    Private Const GWL_STYLE As Integer = -16

    Private Enum ScrollBarDirection
        SB_HORZ = 0
        SB_VERT = 1
        SB_CTL = 2
        SB_BOTH = 3
    End Enum

    ' eat the HScroll when it shows up
    Protected Overrides Sub OnClientSizeChanged(e As EventArgs)
        Dim HScrollVis As Boolean

        HScrollVis = IsHScrollVisible(Me)
        If VerticalScrollOnly AndAlso HScrollVis Then

            ShowScrollBar(MyBase.Handle, ScrollBarDirection.SB_HORZ, False)

        End If

        MyBase.OnClientSizeChanged(e)
    End Sub

    Friend Shared Function IsHScrollVisible(ByVal ctl As Control) As Boolean
        Dim wndStyle As Integer = GetWindowLong(ctl.Handle, GWL_STYLE)
        Return ((wndStyle And WS_HSCROLL) <> 0)
    End Function

End Class
Ňɏssa Pøngjǣrdenlarp
  • 38,411
  • 12
  • 59
  • 178
  • The problem is that the CheckedListBox is filled dynamically out of a SQLite-Database so the design is pretty much fixed. – Broco Jun 30 '14 at 01:03
  • I dont see how the data source comes into play. Or by design, do you mean the UI? Any control you use in replacement can be written to work the same. But if the UI is set in stone are you looking for a magic property? There isnt one. See edit. – Ňɏssa Pøngjǣrdenlarp Jun 30 '14 at 01:19
  • Thanks for the effort, but I don't really know what you mean with "eat the scrollbar". I can deactivate it if I want, that's not the problem. I just thought CheckedListBox has an option I just didn't see because in DataGridView it is possible to automatically wrap text. – Broco Jun 30 '14 at 01:39