views:

1679

answers:

4

I am hoping that someone can help me with a problem I've got at the moment using Compact Framework.Net 2 SP 2.

At the moment I have a UI with a series of text boxes and each textbox displays the contents of a database field. These are shown one beneath another with a scroll bar on the right hand side of the form. Each textbox has a set width which might

I would like to adjust the height each text box based on the number of lines it is holding, the font size and the font in order to avoid using scroll bars on each textbox.

At the moment I am been able to do this in a test application.


Screenshot:


My code:

'Text used in this example:
'TextBox1qwertyuiop lkjhgfdsazxcvbnm1234567890 TextBo

'x1qwer tyuioplkjhgfdsazxcvb nm1234567890

'qwe
'End of exmaple text.

Me.Textbox2.Text = Me.Textbox1.Text

Dim pobjGraphic As Graphics = Me.Textbox2.Parent.CreateGraphics()
Dim pobjSize As SizeF

'Padding values:
Dim piTop As Int32 = 4 'top of text and top of textbox
Dim piBottom As Int32 = 3 'bottom of text and top of textbox

Dim piLines As Int32 = 0

'Based on the font size chosen by the user, create a font to perform the calculation with.
Dim piFontSize As Single = 10

If Me.CheckBox1.Checked.Equals(True) Then
    piFontSize = 6
ElseIf Me.CheckBox2.Checked.Equals(True) Then
    piFontSize = 8
ElseIf Me.CheckBox3.Checked.Equals(True) Then
    piFontSize = 12
Else
    piFontSize = 10
End If

Dim pobjFont As New Font("Tahoma", piFontSize, FontStyle.Regular)

'Calculate the height of one line.
pobjSize = pobjGraphic.MeasureString("HELLO WORLD", pobjFont)
'Value of pobjSize returned: {Width = 71.0 Height = 13.0}


'Calculate the number of lines    
Dim b As Bitmap
b = New Bitmap(1, 1, Imaging.PixelFormat.Format32bppRgb)

'Calculate the number of lines required to display the text properly based on the lenght of the text the width of the control.
'Length of text to show divide by the width of the textbox
piLines = Graphics.FromImage(b).MeasureString(Me.Textbox2.Text, pobjFont).Width / Me.Textbox2.Width
'Value of piLines returned: 2

If piLines = 0 Then
    piLines = 1
End If

'Calculate the size of the text to be displayed using the margins, height of one line and number of lines.
Me.Textbox2.Height = (pobjSize.Height * piLines) + piTop + piBottom
' value produced: 33 = (13 * 2) + 4 + 3
'set font of text box
Me.Textbox2.Font = pobjFont

Finally, I know this can be achieved using a call to the COREDLL.dll using p/invoke but doing this makes the application crash.

Hi Folks,

Below is the pinvoke code as requested:

    <Runtime.InteropServices.DllImport("coredll.dll")> _
Private Function SendMessage( _
    ByVal hwnd As IntPtr, ByVal msg As Integer, _
    ByVal wParam As Integer, ByVal lParam As Integer) As Integer
End Function

<Runtime.InteropServices.DllImport("coredll.dll")> _
Private Function GetCapture() As IntPtr
End Function

<Runtime.InteropServices.DllImport("coredll.dll")> _
Private Function ReleaseCapture() As Boolean
End Function

Public Function GetNumberOfLines(ByVal ptxtCountBox As TextBox) As Integer
    Try
        Dim hnd As IntPtr = New IntPtr

        ptxtCountBox.Capture = True

        ' Capture the textbox handle.
        hnd = GetCapture()
        ptxtCountBox.Capture = False

        ' Get the count of the lines in the box.
        Dim plCount As Integer = SendMessage(ptxtCountBox.Handle, EM_GETLINECOUNT, 0, 0)

        ' Count the number of return lines as we minus this from the total lines to take.
        plCount = plCount - (CharCount(ptxtCountBox.Text, vbCrLf, False))

        plCount += RemoveNonASCIIReturns(ptxtCountBox)

        ReleaseCapture()

        hnd = Nothing

        ' Return the line count.
        Return plCount
    Catch ex As Exception
        GenerateError(msCLASS_NAME, "GetNumberOfLines", ex.Message.ToString)
    End Try
End Function

Thanks,

Morris

A: 

Hi Folks,

Think I got to the bottom of this:

    Public Function GetNumberOfLines(ByVal pstext As String, ByVal pobjfont As Font, ByVal pobjDimensions As Size) As Decimal
    Dim pslines As String() = Nothing
    'Used to measure the string to be placed into the textbox
    Dim pobjBitMap As Bitmap = Nothing
    Dim pobjSize As SizeF = Nothing

    Try
        Dim psline As String = String.Empty
        Dim pilinecount As Decimal = 0.0
        'Spilt the text based on the number of lines breaks.
        pslines = pstext.Split(vbCrLf)
        For Each psline In pslines
            'Create a graphics image which is used to work out the width of the text.
            pobjBitMap = New Bitmap(1, 1, Imaging.PixelFormat.Format32bppRgb)
            pobjSize = Graphics.FromImage(pobjBitMap).MeasureString(psline, pobjfont)

            'If the width of the text is less than 1.0 then add one to the count. This would incidcate a line break.
            If pobjSize.Width < 1.0 Then
                pilinecount = pilinecount + 1
            Else
                'Based on the dimensions of the text, work out the number of lines. 0.5 is added to round the value to next whole number.
                pilinecount = pilinecount + (Round((pobjSize.Width / pobjDimensions.Width) + 0.5))
            End If
        Next

        'If the line count it less than 1 return one line.
        If pilinecount < 1.0 Then
            Return 1.0
        Else
            Return pilinecount
        End If
    Catch ex As Exception
        Return 1.0
    Finally
        If pslines IsNot Nothing Then
            Array.Clear(pslines, 0, pslines.Length - 1)
            pslines = Nothing
        End If
        If pobjBitMap IsNot Nothing Then
            pobjBitMap.Dispose()
        End If
    End Try
End Function

Granted, its a bit of a hack but it appears to work ok at the moment! Any observations or comments on how to improve this are more than welcome.

Also, about the p/invoke stuff, discovered the root of the problem, or rather the solution. Upgraded the .Net fx on my device and that appears to have resolved the issue.

Thanks

Morris

Morrislgn
Forgot to include some extra code where the value returned from the GetNumberOfLines() method is multiplied by the height of a single line of the text in the text box.
Morrislgn
A: 

Well, I would suggest a sound and smart solution to you. Here's is the Algorithm:

  1. Use a Label control for reference.
  2. Assign: • The size of Textbox to the Label. • The font of Textbox to the Label. • Autosize-property of Label to be True. • BorderStyle Property of the Label as of Textbox'. • MinimumSize Property of Label as original size of the Textbox. • MaximumSize Property of Label as Width-same as original and Height to be a large multiple the original height.

  3. Assign the Textbox' Text to Label's text.

  4. Now: if the PrefferdHeight-property of Label > Height of the Textbox == True It's time to increase the height of the Textbox and check the above condition until it’s False.
  5. The Label can be disposed off now.

I have also posted a similar solution in MSDN Forum which can also be checked out: [http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/03fc8e75-fc13-417a-ad8c-d2b26a3a4dda][1]

Regards. :)

A: 

Hi! Neither of the solutions above work. The former fails when there are enough long words as the algorithm doesn't take into account the lost space in wrapping, which I assume the +0.5 is trying to accomodate for. The problem is that the range the "unnecessary space" falls in is a bit too much, so if you increase the accommodating parameter enough to cover even the most extreme cases (cut-out text is quite a huge no-no bug), you'll end up with having extra empty lines in the end of almost every TextBox.

The latter simply doesn't work, since Labels don't have AutoSize in CF either.

I'm personally frantically looking for a solution to this as well, so any help would be much appreciated!!!

Tommi Forsström
A: 

Hi! I asked a similar question and got an answer that completely satisfied my needs on the subject! Please check out stevo3000's answer from my question: http://stackoverflow.com/questions/767335/autosize-for-label-textbox-in-net-compact-framework

He referred to these two blog posts that just completely fixed my problem with one swipe! http://www.mobilepractices.com/2007/12/multi-line-graphicsmeasurestring.html http://www.mobilepractices.com/2008/01/making-multiline-measurestring-work.html

Tommi Forsström