Results 1 to 8 of 8

Thread: Break State

Hybrid View

  1. #1

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    51

    Question Break State

    I'm trying VB.net from Visual Studio 2017 for the first time, not really done much with vb.net for a very long time. Straight away I've hit a problem and I have no idea of the cause or the fix.

    I created a one form app with just a textbox and a numericupdown, the intention being that clicking the updown would cause the height of the textbox to change and also the font size. I've cut this routine down to a minimum just to try to get it to work so it's far from complete...

    Code:
    Public Class Form1  
        Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged  
            txtLargeGridBox.Height = NumericUpDown1.Value  
            Using f As Font = txtLargeGridBox.Font  
                txtLargeGridBox.Font = New Font(f.FontFamily, f.Size + 3, f.Style)  
            End Using  
        End Sub  
    End Class
    There's no other code in the app.

    Whether I just run the code or step thru it makes no difference, it fails on the End Sub saying...

    Your app has entered a break state, but there is no code to show because all threads were executing external code (typically system or framework code).

    Why?

    How do I fix it?

    Thanks all

    Ian

  2. #2
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,299

    Re: Break State

    Firstly, there's no point setting the Height of the TextBox unless you have set Multiline to True. If you haven't, the Height will be purely dependent on the Font.

    As for your issue, I'm guessing that it's because of your use of a Using block. The Font used by the TextBox is likely used elsewhere so disposing it, which is going to happen at that End Using statement, could well be a problem. Get rid of that Using block and just use a standard local variable and I expect that your issue will go away.

  3. #3

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    51

    Re: Break State

    Quote Originally Posted by jmcilhinney View Post
    Firstly, there's no point setting the Height of the TextBox unless you have set Multiline to True. If you haven't, the Height will be purely dependent on the Font.

    As for your issue, I'm guessing that it's because of your use of a Using block. The Font used by the TextBox is likely used elsewhere so disposing it, which is going to happen at that End Using statement, could well be a problem. Get rid of that Using block and just use a standard local variable and I expect that your issue will go away.
    Thanks for your reply, I will certainly give that a try although I don't fully follow why using Using here would cause a problem.
    I'll just add that it does correctly change the height and does correctly change the font size, the only problem seems to be this Break.
    Last edited by IanBrooke; Jan 14th, 2018 at 08:18 PM.

  4. #4
    Super Moderator jmcilhinney's Avatar
    Join Date
    May 2005
    Location
    Sydney, Australia
    Posts
    110,299

    Re: Break State

    Quote Originally Posted by IanBrooke View Post
    I don't fully follow why using Using here would cause a problem.
    It's a bit of an educated guess but, if I'm right, the system is trying to use that same Font object elsewhere but that fails because you have disposed it.
    Quote Originally Posted by IanBrooke View Post
    I'll just add that it does correctly change the height and does correctly change the font size
    Does it though? If you remove the code that changes the Font, does the Height still change? Like I said, the Height of a TextBox is linked to the Size of its Font. If you change the Size of the Font then the Height will change, so you'd see that change. Setting the actual Height property is likely having zero effect. As proof, I just tested this code:
    vb.net Code:
    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2.     TextBox1.Height += 100
    3. End Sub
    4.  
    5. Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
    6.     Dim f = TextBox1.Font
    7.  
    8.     TextBox1.Font = New Font(f.FontFamily, f.Size + 10, f.Style)
    9. End Sub
    Clicking Button1 had no effect on the TextBox while clicking Button2 changed the Font and the Height changed accordingly.

  5. #5

    Thread Starter
    Member
    Join Date
    Jan 2018
    Posts
    51

    Re: Break State

    Quote Originally Posted by jmcilhinney View Post
    It's a bit of an educated guess but, if I'm right, the system is trying to use that same Font object elsewhere but that fails because you have disposed it.

    Does it though? If you remove the code that changes the Font, does the Height still change? Like I said, the Height of a TextBox is linked to the Size of its Font. If you change the Size of the Font then the Height will change, so you'd see that change. Setting the actual Height property is likely having zero effect.
    Umm, Yes it does still change. If I change the code to this:
    Code:
    Private Sub NumericUpDown1_ValueChanged(sender As Object, e As EventArgs) Handles NumericUpDown1.ValueChanged
            Dim f As Font = txtLargeGridBox.Font
            'txtLargeGridBox.Height = NumericUpDown1.Value
            txtLargeGridBox.Font = New Font(f.FontFamily, f.Size + 1, f.Style)
        End Sub
    Notice the "Height changing line" is commented out. This code ONLY changes the font size, the textbox retains the same height. If I remove the comment on height changing and instead comment out font size, then the textbox changes height but the font retains its' size. Similarly if nether line is commented then both the box and font change size, which is what I wanted, although it would have been cool to have it your way and just have to change the font size.
    No idea why we are getting different results but it has, as you said, fixed the problem but I do believe that is a bug.
    Thanks a lot.

  6. #6
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Break State

    I think jmc already pointed out the probably difference.
    Quote Originally Posted by jmcilhinney View Post
    Firstly, there's no point setting the Height of the TextBox unless you have set Multiline to True. If you haven't, the Height will be purely dependent on the Font.
    Likely, you have the textbox MultiLine property set to True. His code example depends on the default setting of MultiLine, which is False.
    Last edited by passel; Jan 15th, 2018 at 01:57 PM.

  7. #7
    Super Moderator si_the_geek's Avatar
    Join Date
    Jul 2002
    Location
    Bristol, UK
    Posts
    41,929

    Re: Break State

    Note that if you want to 'abbreviate' the code (as you were with the Using block) you can use a With block, eg:
    Code:
            With txtLargeGridBox.Font  
                txtLargeGridBox.Font = New Font(.FontFamily, .Size + 3, .Style)  
            End With
    'With' is only a simplification of code, it doesn't do extra hidden work like 'Using' does... so With does not do anything to destroy the variable etc that is involved, whereas Using does.

    However, a local variable (as in the Button2_Click example in the post above) takes less code, so is probably the better choice.

  8. #8
    You don't want to know.
    Join Date
    Aug 2010
    Posts
    4,578

    Re: Break State

    I feel like we kind of got in the weeds and I want to make sure to explain the bug.

    When you use a Using statement, the thing you assign to the variable is guaranteed to be disposed. I think we get that.

    But there are some dangerous things about IDisposable, it's not the best-ever pattern for memory management. If many things have to share a disposable item, odds are someone's going to get unhappy.

    What do I mean? Let's say we have two forms, A and B. And they share the same Font object between them. If A decides it's done with the Font and disposes it, the Font object becomes invalid. But B doesn't know! So when many things have to share the same disposable object, we're responsible for writing extra code to make sure that's handled safely.

    What's being shared? The original Font. Odds are if you haven't manipulated the Font of any controls yourself, all of them are using some default font. The designer code may not even be initializing it. That means the odds are very high there's some standard system font instance they all grab. Windows API is like that: when they designed it 4MB of memory was a luxury, so if there was a way to reuse the same Font for all controls they'd take it.

    But the implication is you should never, ever destroy that one shared system Font, since everything depends on it. If you destroy that Font, the next time ANYTHING in the program tries to draw things are going to go very, very wrong.

    I think that's what happens in your program. Your TextBox isn't the only thing using the particular Font it has at startup. So when you cause that Font to be disposed, the other thing tries to use it and fails.

    (You can recreate this, sometimes. The Brushes class holds a ton of system-wide default brushes. If you try to dispose one of them, bad things often happen.)

    There's not a really good solution that also makes you a good citizen. IDisposable doesn't have a built-in concept of "Can you dispose me?" or "Is someone else referencing me?" It also doesn't have a built-in concept of, "Have I been disposed yet?". Some things in .NET add that, but it's not standard and not part of the interface.

    So I think the safest way to implement code that resizes a TextBox's font would have to keep track of every font it creates itself. At startup, that variable will be Nothing, so in that case it won't dispose anything. For every other situation, it will create a new font, update the TextBox, then dispose the old font:
    Code:
    Private _lastFont As Font = Nothing
    
    Sub WhenSizeShouldChange(...)
        Dim originalFont = yourTextBox.Font
        Dim newFont = New Font(originalFont.FontFamily, originalFont.Size + 1, originalFont.Style)
        yourTextBox.Font = newFont
    
        If _lastFont IsNot Nothing
            _lastFont.Dispose()
        End If
    
        _lastFont = newFont
    End Sub
    Again: this code will only ever try to dispose a Font that it created itself. That's the only Font we know is safe.
    This answer is wrong. You should be using TableAdapter and Dictionaries instead.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width