|
Hi everybody, am going to show you a sample program which enables to print the contents of a datagridview, the program works properly despite a minor error which occurs before the printing is done it says OBJECT REFERENCE NOT SET TO AN INSTANCE OF AN OBJECT, although it does not prevent the program from meeting the purpose. i would like to share it with you, and atleast we can discus on how to remove that error.
The program is based on the customers table of the Northwind Database.
On my form there is a datagridview named Mydatagridview, A print button called btnPrint
Below is the VB code ..............
Imports System.Data.OleDb
Imports System.Drawing.Printing
Imports System
Imports System.Collections
Imports System.ComponentModel
Imports System.Data
Imports System.Text
Imports System.Windows.Forms
Imports System.Drawing
Public Class Form1
Private WithEvents printDocument1 As New PrintDocument
'Used to save left coordinates of columns
Dim arrColumnLefts = New ArrayList()
'Used to save column widths
Dim arrColumnWidths = New ArrayList()
'Used to get and set the datagridview cell height
Dim iCellHeight As Integer = 0
Dim iTotalWidth As Integer = 0
'Used as counter
Dim iCount As Integer = 0
Dim iRow As Integer = 0
'Used to check whether we are printing first page
Dim bFirstPage As Boolean = False
'Used to check whether we are printing a new page
Dim bNewPage As Boolean = False
'Used for the header height
Dim iHeaderHeight As Integer = 0
Dim strFormat = New StringFormat()
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim con As New OleDb.OleDbConnection
con.ConnectionString = "provider=microsoft.jet.oledb.4.0; Data source= " & Application.StartupPath & "\Customers.mdb"
Dim ds As DataSet = New DataSet()
Dim dt As New DataTable
Dim da As OleDbDataAdapter = New OleDbDataAdapter("SELECT CompanyName,ContactName,Address,PostalCode,Phone from Customers2", con)
Me.WindowState = FormWindowState.Maximized
Try
da.Fill(ds, "dt")
da.Fill(ds, "Customers2")
MyDataGridView.DataSource = ds
MyDataGridView.DataMember = "dt"
Catch ex As Exception
MessageBox.Show("Operation failed: " + ex.ToString(), Application.ProductName + " - Error", MessageBoxButtons.OK, MessageBoxIcon.[Error])
Return
End Try
End Sub
Private Sub btnPrint_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPrint.Click
'Open the print dialogue
Dim MyPrintDialog = New PrintDialog()
MyPrintDialog.Document = printDocument1
MyPrintDialog.UseEXDialog = True
'Get the document
If Windows.Forms.DialogResult.OK = MyPrintDialog.ShowDialog() Then
printDocument1.DocumentName = "Test page print"
printDocument1.Print()
End If
End Sub
Private Sub printDocument1_BeginPrint(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintEventArgs) Handles _
printDocument1.BeginPrint
' MsgBox("starting printpage")
Try
strFormat.Alignment = StringAlignment.Near
strFormat.LineAlignment = StringAlignment.Center
strFormat.Trimming = StringTrimming.EllipsisCharacter
arrColumnLefts.Clear()
arrColumnWidths.Clear()
iCellHeight = 0
bFirstPage = True
bNewPage = True
'Calculating Total Widths
iTotalWidth = 0
For Each dgvGridCol As DataGridViewColumn In MyDataGridView.Columns
iTotalWidth = iTotalWidth + dgvGridCol.Width
Next
Catch ex As Exception
MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
Private Sub printDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles _
printDocument1.PrintPage
Try
'Set the left margin
Dim iLeftMargin As Integer = e.MarginBounds.Left
'Set the top margin
Dim iTopMargin As Integer = e.MarginBounds.Top
'Whether more pages have to print or not
Dim bMorePagesToPrint As Boolean = False
Dim iTmpWidth As Integer = 0
'For the first page to print set the cell width and header height
If bFirstPage = True Then
For Each Gridcol As DataGridViewColumn In MyDataGridView.Columns
iTmpWidth = CType(Math.Floor(CType(CType(Gridcol.Width, Double) / CType(iTotalWidth, Double) * CType(iTotalWidth, Double) * (CType(e.MarginBounds.Width, Double) / CType(iTotalWidth, Double)), Double)), Integer)
iHeaderHeight = CType((e.Graphics.MeasureString(Gridcol.HeaderText, Gridcol.InheritedStyle.Font, iTmpWidth).Height) + 11, Integer)
'Save width and height of headers
arrColumnLefts.Add(iLeftMargin)
arrColumnWidths.Add(iTmpWidth)
iLeftMargin = iLeftMargin + iTmpWidth
Next
End If
'Loop till all the grid rows not get printed
While iRow <= MyDataGridView.Rows.Count - 1
Dim GridRow As DataGridViewRow = MyDataGridView.Rows(iRow)
'Set the cell height
iCellHeight = GridRow.Height + 5
Dim iCount As Integer = 0
'Check whether the current page settings allo more rows to print
If iTopMargin + iCellHeight >= e.MarginBounds.Height + e.MarginBounds.Top Then
bNewPage = True
bFirstPage = False
bMorePagesToPrint = True
Exit While
Else
If bNewPage = True Then
'Draw header
e.Graphics.DrawString("Fibre Requirements", New Font(MyDataGridView.Font, FontStyle.Bold), Brushes.Black, e.MarginBounds.Left, e.MarginBounds.Top - e.Graphics.MeasureString("Customer Summary", New Font(MyDataGridView.Font, FontStyle.Bold), e.MarginBounds.Width).Height - 13)
Dim strDate As String = DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToShortTimeString()
'Draw Date
e.Graphics.DrawString(strDate, New Font(MyDataGridView.Font, FontStyle.Bold), Brushes.Black, e.MarginBounds.Left + (e.MarginBounds.Width - e.Graphics.MeasureString(strDate, New Font(MyDataGridView.Font, FontStyle.Bold), e.MarginBounds.Width).Width), e.MarginBounds.Top - e.Graphics.MeasureString("Customer Summary", New Font(New Font(MyDataGridView.Font, FontStyle.Bold), FontStyle.Bold), e.MarginBounds.Width).Height - 13)
'Draw Columns
iTopMargin = e.MarginBounds.Top
For Each GridCol As DataGridViewColumn In MyDataGridView.Columns
e.Graphics.FillRectangle(New SolidBrush(Color.LightGray), New Rectangle(CType(arrColumnLefts(iCount), Integer), iTopMargin, CType(arrColumnWidths(iCount), Integer), iHeaderHeight))
e.Graphics.DrawRectangle(Pens.Black, New Rectangle(CType(arrColumnLefts(iCount), Integer), iTopMargin, CType(arrColumnWidths(iCount), Integer), iHeaderHeight))
e.Graphics.DrawString(GridCol.HeaderText, GridCol.InheritedStyle.Font, New SolidBrush(GridCol.InheritedStyle.ForeColor), New RectangleF(CType(arrColumnLefts(iCount), Integer), iTopMargin, CType(arrColumnWidths(iCount), Integer), iHeaderHeight), strFormat)
iCount = iCount + 1
Next GridCol
bNewPage = False
iTopMargin += iHeaderHeight
End If
iCount = 0
'Draw Columns Contents
For Each Cel As DataGridViewCell In GridRow.Cells
If Not IsDBNull(Cel.Value) Then
e.Graphics.DrawString(Cel.Value.ToString(), Cel.InheritedStyle.Font, New SolidBrush(Cel.InheritedStyle.ForeColor), New RectangleF(CType(arrColumnLefts(iCount), Integer), CType(iTopMargin, Single), CType(arrColumnWidths(iCount), Integer), CType(iCellHeight, Single)), strFormat)
End If
'Drawing Cells Borders
e.Graphics.DrawRectangle(Pens.Black, New Rectangle(CType(arrColumnLefts(iCount), Integer), iTopMargin, CType(arrColumnWidths(iCount), Integer), iCellHeight))
iCount = iCount + 1
Next
End If
iRow = iRow + 1
iTopMargin = iTopMargin + iCellHeight
End While
'If more lines exist, print another page.
If bMorePagesToPrint = True Then
e.HasMorePages = True
Else
e.HasMorePages = False
End If
Catch exc As Exception
MessageBox.Show(exc.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
End Sub
End Class
|
|
|
|
|
Use your debugger to locate the exact point at which the error occurs and then show just that portion of code (within <pre> tags), and the content of all the local variables. Although, the debugger will clearly show you which object reference has not been initialised.
Use the best guess
|
|
|
|
|
Evord wrote: Hi everybody, am going to show you a sample program We have samples on datagridprinters in the Article-section. This isn't a sample, it's a code-dump with a question. Let's focus on the question and solving it, shall we?
Instead of showing "exc.Message", try "exc.ToString()"; that way the messagebox will show on which line the error occured. That'd be easier in tracing the exception than reading the entire code and checking each line.
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
My class is now over. I had an issue with the the assignment. I couldn't get the program to find and display the duplicate random numbers. I've looked for almost two weeks for an answer and I'm hoping that someone here can help me.
This was the assignment:
Present the following report – (you will modify this based on user input and the actual rolls.
Number of dice:2
Number of sides:6
Number of rolls:2
Dice 1 Roll 1 = 5
Dice 2 Roll 1 = 6
Dice 1 Roll 2 = 1
Dice 2 Roll 2 = 1
Number of rolls where all dice were the same: 1
I got everything but the number of rolls where all the dice were the same. Can someone please advise me as to how this should have been done?
Here is a snippet of what I did:
'Start the randomization process
Dim RandomClass As New Random() 'Our random number generator
Dim vRoll() As Integer 'User entered variable for the array
ReDim vRoll(nDice) 'dynamic number entered by the user
Dim cntDice As Integer = 0
Dim myArray As New List(Of Integer)
Dim temp As Integer
myArray.Clear()
'Get the number of rolls and the number of dice and then randomize the rolls.
For i As Integer = 1 To rRoll
For j As Integer = 1 To nDice
temp = RandomClass.Next(1, dSize + 1)
LST_Items.Items.Add("Dice " & j & " Roll " & i & " = " & temp.ToString)
If Not myArray.Contains(temp) Then
cntDice += 1
LBL_Same.Text = cntDice
Else
LBL_Same.Text = "0"
End If
Next
Next
So if anyone is willing to give me advice I would greatly appreciate it.
Thanks!
Troy E Bouchard
|
|
|
|
|
First, you don't need that List. You're not trying to remember every single die roll.
Second, you never compare the roll of the first die to the roll of the second. Once you do that, you simply increment a counter that tracks how many times both dice are equal.
Third, you don't need two for loops, just one.
|
|
|
|
|
You could also sort the list first, then duplicates would show up next to each other.
|
|
|
|
|
Don't need the list at all. Gen the first number on the roll and remember it. For each subsequent die, check it's value against the first die. Finding a non-dupliate is very easy. If you get through the loop withouting finding a non-duplicate, well, you know.
|
|
|
|
|
Hi Guys,
Is it possible to have a list/collection of objects that inherit from a single base object without losing Intelli-sense?
Here is an example of what I mean...
Public Class baseblob
Private _position As PointF
Property position
Get
Return _position
End Get
Set(value)
_position = value
End Set
End Property
Sub New()
position = PointF.Empty
End Sub
End Class
Public Class blob
Inherits baseblob
Sub moveRight(ByVal Distance As Single)
position = New PointF(position.X + Distance, position.y)
End Sub
End Class
Public Class Form1
Dim blob As New blob
Dim blobs As New List(Of baseblob)
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
blob.moveRight(10)
MsgBox(blob.position.x)
blobs.Add(blob)
MsgBox(blobs(0).position.x)
blobs(0).moveright(10)
MsgBox(blobs(0).position.x)
End Sub
End Class
... but of course in the above example i get
'moveright' is not a member of 'oopTest.baseblob'
So it wants me to use
Dim blobs As New List(Of Object)
So it will compile and work as intended...
I just wanted to know is there something I'm missing here? Why can't I just let it know that it's a base object and to list all the possible methods/properties etc of the base class and also any objects that inherit the base class? Give me the lot!
To me it doesn't sound like such a hard thing to ask of the compiler/dev environment... why cant it do it ?
modified 14-May-13 0:36am.
|
|
|
|
|
The method shows up.
In VB.NET, the default access modifier for a class method is Public. In C# it's private.
You'd be better served by not depending on the defaults but explicitly declaring your access levels. Also, your naming convention isn't exactly clean and understandable either. In your example, how do to tell the difference between a variable called blob and your class called blob ?? It should look more like:
Public Class BaseBlob
Private _position As PointF
Public Property Position
Get
Return _position
End Get
Set(value)
_position = value
End Set
End Property
Sub New()
Position = PointF.Empty
End Sub
End Class
Public Class Blob
Inherits BaseBlob
Public Sub MoveRight(ByVal distance As Single)
Position = New PointF(Position.X + distance, Position.y)
End Sub
End Class
Public Class Form1
Private blob As New Blob
Private blobs As New List(Of BaseBlob)
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
blob.MoveRight(10)
MsgBox(blob.Position.x)
blobs.Add(blob)
MsgBox(blobs(0).Position.x)
blobs(0).MoveRight(10)
MsgBox(blobs(0).Position.x)
End Sub
End Class
You can't tell Intellisense to show all members from every class inheriting from a base class. It's not showing you the members of Blob because you told it the collection was a collection of BaseBlob, not Blob. Do you see a member on BaseBlob called MoveRight ?? Nope. So it's not going to show any members that inherit from classes that inherit from BaseBlob because none of them are valid! MoveRight is not applicable to a collection member of blobs because you're are treating the objects in the collection as if they were BaseBlob object. It's telling you that if you try to use one of those members, the compile will fail!
|
|
|
|
|
Thanks for the naming scheme advice. What I use for my project is a lot easier. It was just a quick example. I should have made it easier to read, sorry.
My primary issue is that I need to have multiple class objects that behave differently (playership, enemy drone, missile etc) held in a single container so that my main loop can enumerate through them all.
For example.
For i as integer = 0 to blobs.count - 1
blobs(i).AiTick
blobs(i).Move
blobs(i).Draw
Next i
The only way I could find to do this was to create a base class with the ai/move/draw methods in it and have different classes inherit from the base class and over-ride the base class's methods.
The main issue i have is that these classes that inherit from the base class occasionally have extra methods. I would like to see those when i'm coding things like blobs(0).ExtraMethod like i can for the base class.
I guess what i'm asking isn't possible.
If ClassA inherits BaseClass and ClassB inherits BaseClass but ClassA also has an extra method called "ExtraMethod" then I already run the risk of accidently executing ExtraMethod on the item in the collection that is ClassB and causing an exception. I deal with that issue already in my code, so i don't understand why the dev environment is perfectly fine with me making a list(of Objects) and running List(0).ExtraMethod ... however when I ask it to have a list of BaseClass it doesnt goto the effort of listing what's availiable in any classes that inherit from BaseClass.
I guess I will just continue to have a list(of Object) instead of a list(of BaseClass) and continue running extra methods from classes that inherit from BaseClass as I currently do by first checking the object type.
|
|
|
|
|
Purge1t wrote: I guess what i'm asking isn't possible.
It's not possible because you're trying to violate Object Oriented Programming principles.
You're putting the Move method in one object, when it actually applies to all of the objects. You have to Move the Player, Move the Missle, Move the EnemyDrone, ... Don't use a rather specific MoveRight method. It should be Move and take some kind of value(s) to tell it where to or how far to move. That should go in the Base object that these other objects inherit from.
The same is true for the Draw method. Every object should draw itself, so you pass in a Graphics object that it uses to draw itself on. This is common for every object you mentioned, so it should go in the Base object they are inheriting from, not the specific objects.
By the way, in your case, if you try to execute a method on an object that doesn't implement it, you don't get an exception. You get a compile-time error as the code will not compile.
|
|
|
|
|
Thanks Dave.
Quote: The same is true for the Draw method. Every object should draw itself, so you pass in a Graphics object that it uses to draw itself on. This is common for every object you mentioned, so it should go in the Base object they are inheriting from, not the specific objects.
The PlayerShip class draws a circle, the Missile class draws a triangle and the EnemyDrone class draws a square. How would i know how to depict each different class type if the drawing was done in the base class? Instead of having a MustOverRide .Draw method in the base class that each of the child-classes over-ride ?
|
|
|
|
|
You either have to have that "must override" method or you have to have an interface that every object implements that says justabout the same thing.
You MUST implement something that tells the compiler that "this method is expected in this class" so that you can call it no matter what the class really is.
The drawing is NOT done in the base class. It just provides a "must override" method so that each class can implement it's own drawing code, but since each drawing method implements the exact same method signature, outside code can call it without knowing exactly which type of class it is.
|
|
|
|
|
I am currently trying to convert a String that is gotten from an input box to an Integer using the Try Parse method. The integer is then supposed to be used to fill an array named international. Here is the part of the code that pertains to this:
Dim Count As Integer
For Count = 0 To international.Length - 1
international(Count) = Integer.TryParse(InputBox("Keep entering the sales for each month. If nothing typed, will be interpeted as zero", "New data entry"))
Next Count
I am getting the error message: Overload resolution failed because no accessible 'TryParse' accepts this number of arguments.
How do I fix this?
|
|
|
|
|
|
How to get values from listview and display it to textbox using sql database ?
and then i can update the items in listview using a button..then refresh the listview
after i click the button...all in 1 form
tnx for the help in advance..im just a newbie in vb.net
|
|
|
|
|
Member 10017083 wrote: How to get values from listview Iterate it's items[^].
Member 10017083 wrote: and display it to textbox using sql database ?
You don't display using a database. A database is for storage. To display text in a textbox, change it's text-property.
Member 10017083 wrote: <layer>and then i can update the items in listview using a button..then refresh the listview
after i click the button...all in 1 form
You're describing how the application should work; it'd be a very long post if we'd get detailed into each method you'd be writing. I suggest you start with something simpeler; display some text in a listview, if that works, we can add a button. One step at a time
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Hello.
I am having zero luck finding anything on doing a TreeView1.Nodes.Find() starting from a particular child node. Find() apparently works over the entire tree, and does not let you specify a starting point in the tree.
|
|
|
|
|
treddie wrote: I am having zero luck finding anything on doing a TreeView1.Nodes.Find() starting from a particular child node. Don't trust on luck. Where's your code?
treddie wrote: Find() apparently works over the entire tree, and does not let you specify a starting point in the tree. Trying something like below?
Imports System.Windows.Forms
Module Module1
Private TreeView1 As New TreeView()
Sub Main()
Using f As New Form
Dim btn As New Button
btn.Dock = DockStyle.Top
Dim node1 As TreeNode = TreeView1.Nodes.Add("Node1")
node1.Nodes.Add("Sub1", "Sub1").Nodes.Add("Hello", "Hello")
Dim node2 As TreeNode = TreeView1.Nodes.Add("Node2")
node2.Nodes.Add("Sub1", "Sub1").Nodes.Add("Hello", "Hello")
Dim foundNodes As TreeNode() = node2.Nodes.Find("Hello", True)
If foundNodes.Length > 0 Then
TreeView1.SelectedNode = foundNodes(0)
TreeView1.Focus()
End If
f.Controls.Add(TreeView1)
f.Controls.Add(btn)
f.ShowDialog()
End Using
End Sub
End Module
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
Hey, Eddy.
I probably should have put this post in my other thread, since I thought I was asking a separate question, but it turns out, I'm back to the old topic!
The problem I see with that solution is that it assumes that you know that the answer lies somewhere beneath Node2 and not Node1. In fact, if you don't know, then you either have to
'
1). Search the whole tree and find all instances of "Hello", then look at the full path property to see if it matches a pre-defined path, or
'
2). You have to be able to step through each node with Find(), and searchAllChildren = "False", to prevent the search from going any deeper than one node at a time. It also has to reject any instances of the search name that might occur ABOVE the current node. In the latter case, as far as I can tell, you need to be able to set a child node as a current node, as if it was the parent node so that the search starts from there. But vb.Net offers no way to set a child node to "Current" during a Find().
UPDATE:
If I change your code to the following:
Dim MyNodes(2) As TreeNode
MyNodes(1) = TreeView1.Nodes.Add("Node1")
MyNodes(1).Nodes.Add("Sub1", "Sub1").Nodes.Add("Hello", "Hello")
MyNodes(2) = TreeView1.Nodes.Add("Node2")
MyNodes(2).Nodes.Add("Sub1", "Sub1").Nodes.Add("Hello", "Hello")
Dim foundNodes As TreeNode() = MyNodes(2).Nodes.Find("Hello", True)
If foundNodes.Length > 0 Then
TreeView1.SelectedNode = foundNodes(0)
TreeView1.Focus()
End If
I gain flexibility in how the parent node is defined, but there is still no flexibility in the Find() operation...If instead of:
= MyNodes(2).Nodes.Find("Hello", True)
'
I want to do:
= MyNodes(2).My1stChildNodes(3).Nodes.Find("Hello", True)
I have to set that up explicitly. And it does not seem to be a problem that lends itself to recursion. The only option then, is to set up separate Find() functions for each node depth you want to start at. For a harddrive's directory structure, that could end up being 10-20 separate functions, easily.
modified 12-May-13 6:13am.
|
|
|
|
|
treddie wrote: is that it assumes that you know that the answer lies somewhere beneath Node2 and not Node1. In fact, if you don't know, then you either have to If it's a path, then you'll know where it's located. If it's a random property, you'll have to go and check each item.
treddie wrote: I want to do:
= MyNodes(2).My1stChildNodes(3).Nodes.Find("Hello", True)
TreeView1.Nodes("Node2").Nodes("Sub1").Nodes.Find("Hello") What are you trying to do? This way of solving does not seem to be very helpful/fruitfull
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|
The basic problem is this. In vb6 (and the COM controls as they were carried over into .Net), you have Dir and File List boxes. You could double-click a folder or file name and do something with it. You can do the same thing with a TreeView. The problem starts when you want to save out those selections when you close the program, so that when you come back, the Treeview has the old selections intact. That was no problem with a Dir or file Listbox, because you could simply set the boxes to a desired path name.
The question that comes up might be, "Well, why not stick to using Dir and File ListBoxes, then?" I wanted to do just that to simplify my port-over to vb.Net, and that would have been fine...If not for the fact that Dir/File Listboxes cannot pass the MAX_PATH = 260 barrier. Another problem in vb6, is that the ListBoxes are not Unicode compatible. But even though they are in .Net, the MAX_PATH barrier is still insurmountable.
So, the TreeView is the "only" answer. But there is no way to tell a TreeView to select a given node based either on a fullpath (there is no option for this), or to tell it to go to a particular node index or node handle. The only option is to store the node sequence (like, "1, 3, 2, 7") and count how many child nodes that translates into (4), then go to a sub or function that explicitly utilizes that same amount of nodes, (Nodes(1).Nodes(3),Nodes(2).Nodes(7)) in one or more methods. Now, in my 1/2 hour quick check of folder depths on my c:\ drive, I counted a maximum folder depth of 12, so it could easily be over that amount. That means, bare minimum, I would need 12 separate subs (These are quicky examples, and not debugged):
Private Sub 1Node (ByVal ChildNodes() as Integer)
TreeView1.SelectedNode = TreeView1.Nodes(x)
TreeView1.SelectedNode.Expand()
End Sub
Private Sub 2Nodes (ByVal ChildNodes() as Integer)
TreeView1.SelectedNode = TreeView1.Nodes(x).Nodes(y)
TreeView1.SelectedNode.Expand()
End Sub
Private Sub 3Nodes (ByVal ChildNodes() as Integer)
TreeView1.SelectedNode = TreeView1.Nodes(x).Nodes(y).Nodes(z)
TreeView1.SelectedNode.Expand()
End Sub
And on and on for at LEAST 12 subs. Now, you just know many people will have folder depths much larger than that (And my drives might, too), so where do you stop? 20 subs? 30 subs? 100 Subs?! I would think to be on the safe side and throwing in a safety factor of 3, a bare minimum of 60 Subs. That is hardly elegant, but if that is what I need to do, then that is just the way it is.
I have noticed a very irritating side-effect of all this...Whenever I have a commercial program that uses a TreeView to navigate a media, it never remembers your last selections. So you have to go back every time and reselect everything. Now I know why. So, it was someone here who had made the comment with reference to another thread that has a bearing on this, and I respectfully paraphrase, "...You don't really need that abilty." I NEED IT! . And I have noticed a fair number of other threads on different sites where this problem comes up with no solution. Vb.Net's quantity of properties may be on the heavy side, but the way I look at it, this is one that just really needs to be added, maybe as an overload.
|
|
|
|
|
..... But there is no way to tell a TreeView to select a given node based either on a fullpath (there is no option for this)
So what is preventing you from writing a routine to do this? It is not that hard.
Private Function NodeFromPath(ByVal path As String, ByVal tv As TreeView) As TreeNode
NodeFromPath = Nothing
Dim parts() As String = path.Split(New String() {tv.PathSeparator}, StringSplitOptions.None)
Dim nodes As TreeNodeCollection
nodes = tv.Nodes
Dim found() As TreeNode
For Each part As String In parts
found = nodes.Find(part, False)
If found.Length = 0 Then
Return Nothing
Else
NodeFromPath = found(0)
nodes = NodeFromPath.Nodes
End If
Next
End Function
|
|
|
|
|
JEEZ! That's exactly what I was trying to do! I could not find any references to anything like NodeFromPath, which would have been a huge timesaver there, alone! And with my relative newness to vb.Net, don't think I would have discovered the syntax you used for "Dim parts()" for a very long, long time.
I must confess this one had my head all fouled up.
Sorry, I could not find an emoticon for red-faced.
|
|
|
|
|
treddie wrote: So, the TreeView is the "only" answer. Search CP, and you'll find that a lot of people think something similar.
treddie wrote: so where do you stop? The moment I recognize the repeating pattern; same code, same handler, just a different level. Neat piece o' code that TnTinMan posted, mine would have been longer
Bastard Programmer from Hell
If you can't read my code, try converting it here[^]
|
|
|
|
|