| |
VB.NET - FortgeschritteneComboBox für vorhandene Laufwerke | | | Autor: Dikn | Datum: 21.05.19 17:18 |
| Hallo!
Ich fülle in Load() eine ComboBox mit den aktuell vorhandenen Laufwerken.
Das erste Laufwerk wird ausgewählt.
Mit Protected Overloads Overrides Sub WndProc(ByRef msg As Message) kann ich erkennen, wenn ein Laufwerk hinzugefügt bzw. entfernt wird.
Jetzt möchte ich die Einträge in der ComboBox aktualisieren.
Mein Problem:
wenn ein neues Laufwerk hinzugefügt wird, soll sich die Ansicht der ComboBox nicht ändern.
wenn ein Laufwerk entfernt wird
-> Laufwerk ist nicht das aktuell ausgewählte Laufwerk -> Ansicht der ComboBox soll sich nicht ändern
-> Laufwerk ist das derzeit ausgewählte Laufwerk -> das erste Laufwerk der ComboBox soll angezeigt werden
Wie mache ich das? | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Manfred X | Datum: 21.05.19 17:31 |
| Hallo!
Ich vermute, mit "Ansicht" meinst Du das aktuell selektierte Item.
Du kannst bei jeder Auswahl eines Laufwerks durch den Benutzer in der Combobox
den aktuell selektierten Eintrag (Value) in einer formularglobalen String-Variable
notieren.
Bei einer Änderung der Combobox-Liste prüfst Du, ob dieser Value noch
vorhanden ist und selektierst ihn, sonst das erste Item (index = 0). | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Dikn | Datum: 23.05.19 09:23 |
| Hallo Manfred X!
Vielen Dank für Deine schnelle Antwort!
Mit „Ansicht“ meine ich:
Beim Hinzufügen/Entfernen eines Laufwerks soll im TreeView [trvFolders] die Markierung des ausgewählten Eintrags bestehen bleiben
Wie geht das?
Was kann vereinfacht verbesset werden?
Imports System.IO
Public Class Form1
Dim strSelItem As String
Dim intTypArr(,) As String
Const WM_DEVICECHANGE As Integer = &H219
Const DBT_DEVICEARRIVAL As Integer = &H8000
Const DBT_DEVICEREMOVECOMPLETE = &H8004
Public Class TreeNode
Inherits System.Windows.Forms.TreeNode
Public Path As String
End Class
Public Declare Function LockWindowUpdate Lib "user32.dll" (ByVal hWndLock As _
IntPtr) As Boolean '???
Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
MyBase.WndProc(msg)
If msg.Msg = WM_DEVICECHANGE AndAlso msg.WParam = CType(DBT_DEVICEARRIVAL, _
IntPtr) Then
frmInfo.TextBox1.Text = vbNewLine & "neuen Datenträger erkannt"
frmInfo.intTime = 1
frmInfo.Show
Call setDrives()
cbDrives.SelectedItem = strSelItem
strSelItem = Me.cbDrives.SelectedItem
End If
If msg.Msg = WM_DEVICECHANGE AndAlso msg.WParam = CType( _
DBT_DEVICEREMOVECOMPLETE, IntPtr) Then
frmInfo.TextBox1.Text = vbNewLine & "Datenträger wurde entfernt"
frmInfo.intTime = 1
frmInfo.Show
Call setDrives()
If InStr(strSelItem, "E:") Then
cbDrives.SelectedIndex = 0
strSelItem = Me.cbDrives.SelectedItem
Call setFolders(strSelItem.Substring(strSelItem.Length-3, 2) & "\")
trvFolders.Focus
Else
cbDrives.SelectedItem = strSelItem
End If
End If
End Sub
Private Sub Me_Load(sender As Object, e As System.EventArgs) Handles Me.Load
Call setDrives()
cbDrives.SelectedIndex = 0
strSelItem = Me.cbDrives.SelectedItem
Call setFolders(Directory.GetLogicalDrives.First)
End Sub
Private Sub cbDrives_DrawItem (ByVal sender As Object, ByVal e As _
System.Windows.Forms.DrawItemEventArgs) Handles cbDrives.DrawItem
If Me.cbDrives.DroppedDown = True AND (e.State And DrawItemState.Selected) = _
DrawItemState.Selected Then
e.Graphics.FillRectangle(SystemBrushes.Control, e.Bounds)
Else
e.Graphics.FillRectangle(SystemBrushes.Window, e.Bounds)
End If
If intTypArr Is Nothing Then Exit Sub
e.Graphics.DrawImage(ImageList2.Images.Item(CInt(intTypArr(e.Index,1))), 4, _
e.Bounds.Top + 1)
e.Graphics.DrawString(cbDrives.Items(e.Index).ToString, cbDrives.Font, _
Brushes.Black, 20, e.Bounds.Top + 1)
End Sub
Private Sub cbDrives_DropDownClosed (sender As Object, e As System.EventArgs) _
Handles cbDrives.DropDownClosed
Me.trvFolders.Nodes.Clear
strSelItem = Me.cbDrives.SelectedItem
Call setFolders(strSelItem.Substring(strSelItem.Length-3,2) & "\")
trvFolders.Focus
End Sub
Private Sub setFolders(strLW As String)
Dim tn As TreeNode = Nothing
Dim nodeInfo As DirectoryInfo = New DirectoryInfo(strLw)
Try
trvFolders.Nodes.Clear
For Each di As DirectoryInfo In nodeInfo.GetDirectories
If di.Attributes = FileAttributes.Directory Then
tn = AddNode(trvFolders.Nodes, di.Name, di.FullName)
If My.Computer.FileSystem.GetDirectories(tn.Path).Count > 0 Then
AddNode(tn.Nodes, ".", ".")
End If
End If
Next
Catch ex As Exception
End Try
End Sub
Private Function AddNode (ByVal nodeCollection As TreeNodeCollection, ByVal _
Caption As String, ByVal path As String) As TreeNode
Dim tn As New TreeNode()
tn.Text = Caption
tn.Path = path
nodeCollection.Add(tn)
Return tn
End Function
End Class | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Dikn | Datum: 23.05.19 09:24 |
| Private Sub setDrives()
Try
Erase intTypArr
cbDrives.Items.Clear
ReDim Preserve intTypArr(DriveInfo.GetDrives.Length - 1, 1)
Dim i As Integer = 0
For Each d As DriveInfo In DriveInfo.GetDrives
Select Case d.DriveType
Case DriveType.Unknown
intTypArr(i,0) = " Unknown (" & d.Name.Substring(0, 2) & ")"
intTypArr(i,1) = "1"
Case DriveType.Fixed
If Asc(d.Name.Substring(0,1)) > 68 Then
intTypArr(i,0) = " " & d.VolumeLabel & " (" & d.Name.Substring(0, _
2) & ")"
intTypArr(i,1) = "4"
Else
intTypArr(i,0) = " Laufwerk (" & d.Name.Substring(0, 2) & ")"
intTypArr(i,1) = "3"
End If
Case DriveType.Network
intTypArr(i,0) = " Netzlaufwerk (" & d.Name.Substring(0, 2) & ")"
intTypArr(i,1) = "4"
Case DriveType.CDRom
If d.IsReady = False Then Continue For
intTypArr(i,0) = " DVD-RW-Laufwerk (" & d.Name.Substring(0, 2) & ")"
intTypArr(i,1) = "5"
Case DriveType.Ram
intTypArr(i,0) = " Ram (" & d.Name.Substring(0, 2) & ")"
intTypArr(i,1) = "5"
Case DriveType.Removable
If d.IsReady = False Then Continue For
intTypArr(i,0) = " " & d.DriveType.ToString & " (" & d.Name.Substring( _
0, 2) & ")"
If d.Name = "A:\" OR d.Name = "B:\" Then
intTypArr(i,1) = "2"
Else
intTypArr(i,1) = "6"
End If
End Select
Me.cbDrives.Items.Add(intTypArr(i,0))
i += 1
Next
Catch ex As Exception
MsgBox("Fehler: " & ex.ToString, MsgBoxStyle.Information, "Fehler in" & _
"'setDrives()'")
End Try
End Sub | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Manfred X | Datum: 23.05.19 13:38 |
| Hallo!
Verwende: Option Strict On
Deine Programme arbeiten sonst nach dem Zufallsprinzip.
Die Zuweisung eines Objekts auf die String-Variable "strSelItem" ist
explizit zu konvertieren.
strSelItem = cbdrives.SelectedItem.ToString
"Instr"-Methode liefert einen Integer-Wert und keinen Boolean.
Also entweder eine korrekte Abfrage durchführen oder die Contains- bzw.
Startswith-Methode nutzen.
In der Gesamtheit habe ich den Code nicht getestet. Zu viele fehlende Angaben.
Der Code zur Reaktion auf das Entfernen eines Laufwerks sollte etwa so aussehen:
If msg.Msg = WM_DEVICECHANGE AndAlso
msg.WParam = CType(DBT_DEVICEREMOVECOMPLETE, IntPtr) Then
Call setDrives()
If cbdrives.Items.Contains(strSelItem) Then
If InStr(strSelItem, "E:") > 0 Then
'???????????
cbdrives.SelectedIndex = 0
strSelItem = Me.cbdrives.SelectedItem.ToString
Else
'Das in der Combo gewählte Item ist noch vorhanden
cbdrives.SelectedItem = strSelItem
End If
Else
'Das in der Combo gewählte Item ist entfernt worden
cbdrives.SelectedIndex = 0
strSelItem = cbdrives.SelectedItem.ToString
End If
End If Schau Dir Datenbindung an: Eine List(Of String) kann man an die Combobox binden.
Beitrag wurde zuletzt am 23.05.19 um 13:45:21 editiert. | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Dikn | Datum: 25.05.19 09:59 |
| Hallo Manfred X!
Vielen Dank für Deine Tipps! Werde sie zukünftig beachten.
Zu Deine Vorschlag: Muss es nicht If InStr(strSelItem, „E:“)) "=" 0 heißen?
Ich habe jetzt folgende Lösung:
Protected Overloads Overrides Sub WndProc(ByRef msg As Message)
MyBase.WndProc(msg)
If msg.Msg = WM_DEVICECHANGE AndAlso msg.WParam = CType(DBT_DEVICEARRIVAL, _
IntPtr)
LockWindowUpdate(CType(0, System.IntPtr))
If cbDrives.DroppedDown = True Then
cbDrives.DroppedDown = False
Call setDrives()
cbDrives.DroppedDown = True
Else
Call setDrives()
End If
cbDrives.SelectedItem = strSelItem
LockWindowUpdate(CType(0, System.IntPtr))
End If
If msg.Msg = WM_DEVICECHANGE AndAlso msg.WParam = CType( _
DBT_DEVICEREMOVECOMPLETE, IntPtr) Then
LockWindowUpdate(CType(Me.Handle.ToInt32, System.IntPtr))
If cbDrives.DroppedDown = True Then
cbDrives.DroppedDown = False
Call setDrives()
cbDrives.DroppedDown = True
Else
Call setDrives()
End If
If cbDrives.Items.Contains(strSelItem) Then
cbDrives.SelectedItem = strSelItem
Else
frmInfo.TextBox1.Text = "Das aktuell angezeigte Laufwerks wurde entfernt"
frmInfo.intTime = 1
frmInfo.Show
cbDrives.SelectedIndex = 0
strSelItem = cbDrives.SelectedItem.ToString
Call setFolders(strSelItem.Substring(strSelItem.Length-3,2) & "\")
LockWindowUpdate(CType(0, System.IntPtr))
End If
End If
End Sub Bitte schau mal darüber… Ich bin dankbar für jeden Tipp.
Was für Angaben fehlen? | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Manfred X | Datum: 25.05.19 12:45 |
| Hallo!
Die alte Instr-Funktion liefert 0 wenn der gesuchte String nicht gefunden wird,
sonst einen Wert > 0.
Ich würde die Management-Konsole nutzen, etwa so:
Imports System
Imports System.IO
Imports System.Management 'Verweis auf Assembly System.Management.DLL ist
' erforderlich !!!!
Public Class frmDrives2
Dim WithEvents watcher As New ManagementEventWatcher
Dim lstdrives As New List(Of String)
Dim bsDrives As New BindingSource With {.DataSource = lstdrives}
Dim WithEvents cboDrives As New ComboBox With
{.Parent = Me, .Width = 200, .Left = 5, .Top = 5,
.DropDownStyle = ComboBoxStyle.DropDown, .DataSource = bsDrives}
Dim SelectedDrive As String = ""
Public Enum USBAction
inserted = 2
removed = 3
End Enum
Private Sub frmDrives2_Load(sender As Object, e As EventArgs) Handles _
MyBase.Load
FillDrivelist()
Dim query As WqlEventQuery = New
WqlEventQuery("SELECT * FROM Win32_VolumeChangeEvent WHERE EventType =" & _
"2 or EventType = 3")
watcher.Query = query
watcher.Start()
End Sub
Private Sub watcher_EventArrived(sender As Object,
e As EventArrivedEventArgs) Handles watcher.EventArrived
Dim et As Short = CShort(e.NewEvent.Properties("EventType").Value)
Dim driveName As String = e.NewEvent.Properties( _
"DriveName").Value.ToString
Dim eventName As String = [Enum].GetName(GetType(USBAction), et)
If et = USBAction.inserted Then
For Each drv As DriveInfo In IO.DriveInfo.GetDrives
If drv.Name.StartsWith(driveName) Then
lstdrives.Add(driveName & " " & drv.DriveType.ToString)
End If
Next drv
lstdrives.Sort()
Else
For i As Integer = lstdrives.Count - 1 To 0 Step -1
If lstdrives(i).StartsWith(driveName) Then lstdrives.RemoveAt(i)
Next i
End If
cboDrives.Invoke(New MethodInvoker(AddressOf SetDriveBinding))
End Sub
Private Sub SetDriveBinding()
bsDrives.ResetBindings(False)
SetSelectedDrive()
End Sub
Private Sub FillDrivelist()
lstdrives.Clear()
For Each drv As DriveInfo In IO.DriveInfo.GetDrives
lstdrives.Add(drv.Name & " " & drv.DriveType.ToString)
Next drv
lstdrives.Sort()
bsDrives.ResetBindings(False)
End Sub
Private Sub SetSelectedDrive()
Dim found As Boolean
If String.IsNullOrEmpty(SelectedDrive) Then Exit Sub
If lstdrives.Count = 0 Then Exit Sub
For i As Integer = 0 To lstdrives.Count - 1
If lstdrives(i).StartsWith(SelectedDrive) Then
cboDrives.SelectedIndex = i : found = True
End If
Next i
If Not found Then cboDrives.SelectedIndex = 0
End Sub
Private Sub cboDrives_SelectedIndexChanged(sender As Object,
e As EventArgs) Handles cboDrives.SelectedIndexChanged
If cboDrives.SelectedItem Is Nothing Then
SelectedDrive = ""
Else
SelectedDrive = cboDrives.SelectedItem.ToString
End If
End Sub
End Class | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Dikn | Datum: 27.05.19 09:20 |
| Hallo Manfred!
Vielen, vielen Dank für Deine Bemühung!
Ich hab‘s ausprobiert… funktioniert wunderbar
Die Management Konsole ist mir bisher völlig unbekannt
Ich hoffe, ich nerve nicht, noch folgende Fragen
- wie kann ich die Events einer vorhandenen ComboBox zuweisen?
- wenn ´ein Laufwerk entfernt wird und das DropDown geöffnet ist
wird die DropDown-Höhe nicht angepasst. Wie kann man das ändern?
- wenn das aktuell ausgewählte Laufwerk entfernt wird, soll das erste Laufwerk
in lstDrives ausgewählt werden.
Zu Deinem Script:
??? Notwendig ???
Dim eventName As String = [Enum].GetName(GetType(USBAction), et)
Ich habe
lstdrives.Add(driveName & " " & drv.DriveType.ToString)
ersetzt mit
lstdrives.Add(drv.Name & " " & drv.DriveType.ToString) | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Manfred X | Datum: 27.05.19 12:49 |
| Was genau meinst Du, wenn Du Events einer vorhandenen Combobox
zuweisen möchtest? Eventhandler-Routinen werden von Windows immer für die
Klasseninstanzen aufgerufen, die entweder durch Handles-Klausel oder
Addhandler dem entsprechenden Klassen-Event im Code zugewiesen worden sind.
Bei mir (Windows10/64Bit, Visual Studio 2017, Framework 4.8, CPU-Typ x86)
wird das geöffnete Dropdown-Fenster der Combobox automatisch vergrößert,
wenn sich die Liste durch das Hinzufügen eines lokalen Laufwerks verlängert
(Basis: Reset der Datenbindung durch Bindingsource: neues Einlesen der Liste).
Beim Entfernen des in der Combobox selektierten Laufwerks wird in meinem
Beispiel das erste Laufwerk in der Liste (Index 0) gewählt. Das erledigt
die Routine "SetSelectedDrive".
Die Variable "Eventname" habe ich in das Beispiel aufgenommen, damit eine
Benachrichtigung des Users beim Hinzufügen/Entfernen eines lokalen Laufwerks
möglich wird:
MessageBox.Show("Drive " & eventName & ": " & driveName) | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Dikn | Datum: 27.05.19 17:43 |
| Ich habe in meinem Formular „frmMain“ bereits eine ComboBox „cbDrives“.
Wie kann ich die mit deinem Vorschlag nutzen?
Das Dropdown-Fenster der Combobox wird auch bei mir automatisch vergrößert, wenn sich die Liste durch das Hinzufügen eines lokalen Laufwerks verlängert.
Aber:
Beim Herausnehmen eine Laufwerks wird der Eintrag gelöscht, aber das Dropdown-Fenster wird nicht verkleinert.
Beim Entfernen des in der Combobox selektierten Laufwerks wird
bei mir wird nicht das erste Laufwerk ausgewählt, sondern das vorige
z.B.:
C:\Fixed
D:\CDRom
E:\Removable
-> E:\Removable wird entfernt -> D:\CDRom wird ausgewählt | |
Re: ComboBox für vorhandene Laufwerke | | | Autor: Manfred X | Datum: 27.05.19 18:21 |
| Was machst Du eigentlich?
Eine Combobox macht man auf, wählt den Eintrag und macht sie zu.
Man läßt diese Liste nicht offen.
Wieso soll die DropdownList direkt optisch auf Drive-Änderungen reagieren?
Setze die Dropdownstyle-Eigemschaft der Combobox auf DropDownlist und
ergänze folgenden Code:
Private Sub SetDriveBinding()
bsDrives.ResetBindings(False)
Dim droppeddown As Boolean
With cboDrives
If .DroppedDown Then
'Dropdown ggf. schließen
.DroppedDown = False
droppeddown = True
End If
End With
SetSelectedDrive(droppeddown)
End Sub
Private Sub SetSelectedDrive(droppeddown As Boolean)
Dim found As Boolean
If String.IsNullOrEmpty(SelectedDrive) Then Exit Sub
If lstdrives.Count = 0 Then Exit Sub
For i As Integer = 0 To lstdrives.Count - 1
If lstdrives(i).StartsWith(SelectedDrive) Then
cboDrives.SelectedIndex = i : found = True
End If
Next i
If Not found Then cboDrives.SelectedIndex = 0
'Dropdown ggf. wieder öffnen
cboDrives.DroppedDown = droppeddown
End Sub Einbinden der Combobox:
Die Bindingsource der Datasource-Eigenschaft Deiner Combobox zuweisen.
Den Invoke-Aufruf auf die Eigenschaft Deiner Combo umsetzen.
Die Handles-Klausel der SelectedIndexChanged-HandlerRoutine auf Deine Combobox umsetzen.
Den obigen Code für Deine Combo umbenennen. | |
| Sie sind nicht angemeldet! Um auf diesen Beitrag zu antworten oder neue Beiträge schreiben zu können, müssen Sie sich zunächst anmelden.
Einloggen | Neu registrieren |
|
|
sevGraph (VB/VBA)
Grafische Auswertungen
Präsentieren Sie Ihre Daten mit wenig Aufwand in grafischer Form. sevGraph unterstützt hierbei Balken-, Linien- und Stapel-Diagramme (Stacked Bars), sowie 2D- und 3D-Tortendiagramme und arbeitet vollständig datenbankunabhängig! Weitere InfosTipp des Monats Access-Tools Vol.1
Über 400 MByte Inhalt
Mehr als 250 Access-Beispiele, 25 Add-Ins und ActiveX-Komponenten, 16 VB-Projekt inkl. Source, mehr als 320 Tipps & Tricks für Access und VB
Nur 24,95 EURWeitere Infos
|