【问题标题】:Issue with Dictionary type, If gived a specific text then get the equivalent dictionary key or dictionary value?字典类型的问题,如果给定特定文本,则获取等效的字典键或字典值?
【发布时间】:2013-07-01 20:02:50
【问题描述】:

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

例如:

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

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

一些图片来理解它:

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

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

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

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

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

...这是我的代码:

(请阅读cmets)

    ' 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

【问题讨论】:

  • 大量的图形和大量的文字。问题是什么?没有一个问号。

标签: .net vb.net winforms listview dictionary


【解决方案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 在第一次匹配时停止。

【讨论】:

    【解决方案2】:

    如果这是我的应用程序,我会将 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
    

    【讨论】:

    • 感谢您的宝贵时间,但我不适合使用 datagridview,我使用的是扩展的 istview,我使用事件和函数等“内部”自定义进行了编码,我不想尝试将其重写为数据网格并更改表单的完整代码。我认为我的小问题可以通过使用 ctype 或一些带有字典的 tryparse 来解决,但非常感谢您的回答。
    • 我已经用我正在使用的解决方案更新了我的答案,也许你可以告诉我是否可以改进它。你的代码真的很有趣,学习和玩 datagridviews 但这次我真的不能,谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多