Method to “remember” past entries

匿名 (未验证) 提交于 2019-12-03 10:10:24

问题:

Part of an application I'm building in VB has terminal functionality, and I'd like to add functionality to it so it remembers past commands in chronological order, similarly to how a windosw terminal works.

In short I'd like you to be able to press the up arrow when the text area is focused and be able to cycle through a list of commands that were entered previously.

I had two ideas for how to do this:

  1. A combobox that, when you hit enter, reads whatever is in combobox.text, whether that be a newly entered command or an old one that was selected. Then add that command to the items of the combobox so you could scroll up and find it again.

  2. Simply a textbox that, when the up arrow is pressed, cycles through some stored queue and sets the text accordingly. This would requires a second queue to remember the cycled through commands and replace them, correct?

Are there any built-in structures of Visual Basic that would be better for this, or is there some better way of doing it?

Thanks for your help.

回答1:

It sounds like you are looking for something like a Most Recently Used List.

You idea for the ComboBox is probably generally the right thing to do. To do what you suggest with a TextBox would largely result in...a ComboBox.

Considerations:

  • Is it is case sensitive? Does FooBar match fooBar?
  • A Stack (or Queue) is not the right tool for this because if they use something from index 4 in the list, there is no easy way to move that item from #4 to #1.
  • To use this with a ComboBox as the UI picker, you want to use something that will work as a binding source.

Here is a nascent MRU class:

Public Class MRUList      Private myList As BindingList(Of String)      Public ReadOnly Property DataList As BindingList(Of String)         Get             Return myList '.Select(Function(f) f.Value).ToList         End Get     End Property      Private myCapacity As Integer      Public Sub New(capacity As Integer)         myCapacity = capacity         myList = New BindingList(Of String)     End Sub      Public Overloads Sub Add(item As String)          Dim ndx As Integer = IndexOfKey(item)          If ndx >= 0 Then             myList.RemoveAt(ndx)         End If          myList.Insert(0, item)          If myList.Count > myCapacity Then             myList.RemoveAt(myList.Count - 1)         End If     End Sub      ' case insensitive search     Private Function IndexOfKey(s As String) As Integer          Return myList.ToList.FindIndex(Function(f) f.Equals(s,                    StringComparison.InvariantCultureIgnoreCase))      End Function  End Class
  • When they pick an existing item, it moves from whence it was to the top of the list.
  • It is case insensitive, "Able" matches "ABLE". But it is case-aware: if/when they type an item again, it uses the new casing. So if "ZIggy" is in the list at slot 3, if they type in "Ziggy" correctly, they old one is removed and the new one used.
  • There is a capacity limiter so you wont get absurdly long lists. When the lists gets too long, old items are dropped.
  • It is built from a BindingList(Of String) so that you can bind it to a Listbox or ComboBox.

The List management is pretty wasteful under the hood. Each time we insert a new item at myList(0) .NET has to shift and jigger the underlying array around. The ideal collection type would be a LinkedList, but that wont work as a binding source and I dont suspect you will have 1000s of items being stored.

Usage:

Private myMRU As New MRUList(8) ... ' bind to CBO in form_load: cboMRU.DataSource = myMRU.DataList

As things are added to the list they will automatically appear in the list. When the user makes a selection

Private Sub cboMRU_Leave(sender As Object, e As EventArgs) Handles cboMRU.Leave     If cboMRU.Text.Length = 0 Then Exit Sub      Dim thisCmd As String = cboMRU.Text     myMRU.Add(thisCmd)     cboMRU.Text = ""  End Sub

I used the Leave event because they can pick from the list or select an item from the list. You code doesn't need to do anything as far as checking for new vs existing items, the Add method does that for you.

On the left, I entered 4 items, Delta being the last one. Next, I typed in Able correctly. The class removed the old one and floated the new one to the top as the MRU with the new spelling.

Since these mean something to your code, use thisCmd in the event for whatever they are. For more complex things, perhaps where what they type is just a key or token for something else, use a BindingList(of TokenItem) in the MRU Class



回答2:

Better than a queue would be an array. The queue allow only sequential access, and after you dequeue it, the object you dequeue get "lost". If you want save it and have also in future session, you can use a file, such cookie or what I prefere, also because prepare the ground for future expansions, an embedded database, such sqlite or firebird. The second one is an incredible powerful database, that allow if you want to get a server, a powerful server



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!