-
Jan 14th, 2018, 04:17 PM
#1
Thread Starter
Member
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
-
Jan 14th, 2018, 06:46 PM
#2
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.
-
Jan 14th, 2018, 07:58 PM
#3
Thread Starter
Member
Re: Break State
Originally Posted by jmcilhinney
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.
-
Jan 14th, 2018, 09:37 PM
#4
Re: Break State
Originally Posted by IanBrooke
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.
Originally Posted by IanBrooke
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:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click TextBox1.Height += 100 End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click Dim f = TextBox1.Font TextBox1.Font = New Font(f.FontFamily, f.Size + 10, f.Style) End Sub
Clicking Button1 had no effect on the TextBox while clicking Button2 changed the Font and the Height changed accordingly.
Last edited by jmcilhinney; Jan 14th, 2018 at 09:40 PM.
-
Jan 15th, 2018, 11:57 AM
#5
Thread Starter
Member
Re: Break State
Originally Posted by jmcilhinney
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.
-
Jan 15th, 2018, 01:54 PM
#6
Re: Break State
I think jmc already pointed out the probably difference.
Originally Posted by jmcilhinney
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.
-
Jan 15th, 2018, 05:39 AM
#7
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.
-
Jan 15th, 2018, 08:03 PM
#8
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|