3

我有一个字典(字符串,字符串),我使用字典值设置目录路径,并使用键为每个值设置描述。

例如:

Value of a random item of my dictionary: "C:\Test"
Key name of that item = "Test folder"

好吧,现在在我的应用程序中,我可以选择是否更喜欢显示描述或完整目录路径,这就是问题所在......

一些图像来理解它:

1 - 我在这里存储/管理我的字典项目:

在此处输入图像描述

2 - 我可以调整此复选框以在组合框中显示字典键或字典值(您将在下一张图片中看到):

在此处输入图像描述

3 - 描述复选框被选中,然后描述显示在组合框中,当我添加一个项目时,它会与选定的combobox.text一起添加(可以是描述或完整路径)

在此处输入图像描述

4 - 现在我取消选中描述复选框,我想要更改列表视图的描述,就像我将组合框的描述更改为等效的完整路径一样(但我更改组合框名称的方法是重新加载字典因为是按字母顺序排序的所以......我不知道如何对列表视图子项做同样的事情)

在此处输入图像描述

我想记住你,listview 子项文本可以是描述,也可以是完整路径,所以我需要在这两种选择中进行这种改变思考。

...这是我的代码:

(请阅读评论)

    ' First of all
    ' "Item.SubItems(2).Text" can be the description or it can be the full path, so I need to do it with both alternatives

    If ListView_Monitor.Items.Count <> 0 Then

        For Each Item As ListViewItem In ListView_Monitor.Items

            If ShowDescriptions Then ' Showdescription is a boolean var to show descriptions or full paths

                ' Description is stored in the "Dictionary.Key"
                ' I don't know how to get the key name of the item

                ' Item.SubItems(2).Text = Directories_SendTo.keys  ... ...
                ' CType(Item.SubItems(2).Text, Directories_SendTo... ...)

            ElseIf Not ShowDescriptions Then ' Don't show descriptions, I will show fullpaths

                ' Fullpath is stored in the "Dictionary.Value"

                ' Remember that "Item.SubItems(2).Text" can be the description or the fullpath
                ' So if "Item.SubItems(2).Text" is the description then this piece of code works, 'cause the dictionary keyname is the same as the description name 
                Item.SubItems(2).Text = Directories_SendTo(Item.SubItems(2).Text)

                ' Here I need an alternative if "Item.SubItems(2).Text" is the directory path and not the description
            End If

        Next

    End If

更新:

解决方案(暂时)...

我的问题是我是否可以改进这段代码(也许不要在字典内循环):

        If ListView_Monitor.Items.Count <> 0 Then

            For Each Item As ListViewItem In ListView_Monitor.Items

                If ShowDescriptions Then ' Show descriptions

                    For Each value In Directories_SendTo.Values
                        If value = Item.SubItems(2).Text Then
                            Item.SubItems(2).Text = FindKeyByValue(Directories_SendTo, Item.SubItems(2).Text)
                        End If
                    Next

                ElseIf Not ShowDescriptions Then ' Show fullpaths

                    For Each key In Directories_SendTo.Keys
                        If key = Item.SubItems(2).Text Then
                            Item.SubItems(2).Text = Directories_SendTo(key)
                        End If
                    Next

                End If

            Next

        End If

   Public Function FindKeyByValue(Of TKey, TValue)(dictionary As Dictionary(Of TKey, TValue), value As TValue) As TKey

        For Each pair As KeyValuePair(Of TKey, TValue) In dictionary
            If value.Equals(pair.Value) Then Return pair.Key
        Next

        ' Throw New Exception("The value is not found in the dictionary.")
        Return Nothing
    End Function
4

2 回答 2

1

如果这是我的应用程序,我会将 UI 元素更改为 datagridview,以便我可以绑定包含自定义类的集合,并根据需要隐藏或显示适当的列。

这种方法将允许您在将来轻松添加其他属性列,而不必担心您当前面临的问题。它还允许您将 UI 扩展到其他平台(移动、Web),而无需在 UI 中使用大量硬编码信息。

例如,我将创建以下类和集合来保存有关文件的信息:

Public Class FileDetails
    Public Property Index As Integer
    Public Property Description As String = String.Empty
    Public Property FullFileName As String = String.Empty
    Public ReadOnly Property FileName As String
        Get
            If Not String.IsNullOrEmpty(Me.FullFileName) Then
                Return System.IO.Path.GetFileName(Me.FullFileName)
            Else
                Return String.Empty
            End If
        End Get
    End Property
    Public ReadOnly Property Directory As String
        Get
            If Not String.IsNullOrEmpty(Me.FullFileName) Then
                Return System.IO.Path.GetDirectoryName(Me.FullFileName)
            Else
                Return String.Empty
            End If
        End Get
    End Property
End Class

Public Class FileDetailsCollection
    Inherits System.ComponentModel.BindingList(Of FileDetails)

End Class

这是我将在表单级别声明以保存信息的私有成员变量:

Private m_Collection As FileDetailsCollection

此方法用于使用一些示例数据填充集合:

Private Sub LoadCollection()
    Dim wIndex As Integer
    m_Collection = New FileDetailsCollection
    For Each sFileName As String In System.IO.Directory.GetFiles("c:\", "*.*")
        Dim oFileDetails As New FileDetails

        oFileDetails.FullFileName = sFileName
        wIndex += 1
        oFileDetails.Index = wIndex
        oFileDetails.Description = "Test " & wIndex.ToString

        m_Collection.Add(oFileDetails)
    Next
End Sub

此方法在网格上执行初始配置,包括将显示的列的定义:

Private Sub ConfigureGrid()
    With Me.DataGridView1
        .AutoGenerateColumns = False
        .Columns.Add(New DataGridViewTextBoxColumn With {.DataPropertyName = "Index", .Name = .DataPropertyName, .HeaderText = "Index"})
        .Columns.Add(New DataGridViewTextBoxColumn With {.DataPropertyName = "FullFileName", .Name = .DataPropertyName, .HeaderText = "Song"})
        .Columns.Add(New DataGridViewTextBoxColumn With {.DataPropertyName = "Description", .Name = .DataPropertyName, .HeaderText = "Description"})
        .Columns.Add(New DataGridViewTextBoxColumn With {.DataPropertyName = "Directory", .Name = .DataPropertyName, .HeaderText = "Description"})

        .DataSource = m_Collection
    End With
End Sub

此方法为当前选项更改配置可见列(这相当于您的复选框):

Private Sub ConfigureColumnsForOptionChange()

    With Me.DataGridView1
        .Columns("Description").Visible = CheckBox1.Checked
        .Columns("Directory").Visible = Not CheckBox1.Checked
    End With
End Sub

最后,我们执行初始化和表单启动:

Sub New()

    ' This call is required by the designer.
    InitializeComponent()

    Call LoadCollection()
    Call LoadGrid()
    Call ConfigureColumnsForOptionChange()

End Sub

并在用户更改复选框值时更新 UI:

Private Sub CheckBox1_CheckedChanged(sender As System.Object, e As System.EventArgs) Handles CheckBox1.CheckedChanged
    Call ConfigureColumnsForOptionChange()
End Sub
于 2013-07-04T00:39:10.067 回答
1

要回答你的第二个问题,关于如何改进你正在使用的循环,它可以得到显着改进。目前,如果列表视图中有 100 个项目,目录中有 10 个项目,则您的代码将循环至少 1000 次,并且可能循环最多 10 次,具体取决于目录中使用的值以及是否 ShowDescriptions被标记。

我们可以通过在进入赋值循环之前通过适当的键构建字典来将直接循环减少到 110 次:

    If ListView_Monitor.Items.Count <> 0 Then
        Dim DirectoriesByCurrentKey As New Dictionary(Of String, String)

        If ShowDescriptions Then
            ' If we are showing the descriptions, add each of the items to the new collection, keyed by the value
            For Each key In Directories_SendTo.Keys
                Dim Description As String
                Description = Directories_SendTo(key)
                ' We don't know if description is unique, so make sure that we don't get a runtime error if we 
                ' try to add the same description multiple time
                If Not DirectoriesByCurrentKey.ContainsKey(Description) Then
                    DirectoriesByCurrentKey.Add(Description, key)
                End If
            Next
        Else
            ' Just use the current collection
            DirectoriesByCurrentKey = Directories_SendTo
        End If

        For Each Item As ListViewItem In ListView_Monitor.Items
            Dim sDescription As String = ""
            ' Try to find the current description using the current list item description
            If DirectoriesByCurrentKey.TryGetValue(Item.SubItems(2).Text, sDescription) Then
                ' If we found the entry, change the description to what we found
                Item.SubItems(2).Text = sDescription
            End If
        Next
    End If

请注意,因为我们不知道描述是否唯一,所以我们需要在添加之前测试它是否存在于新字典中。这将导致与您当前的行为相同,因为您的 FindKeyByValue 在第一次匹配时停止。

于 2013-07-04T17:02:47.340 回答