前几天,我问如何在课堂上创建一个消息框,但其中一个答案是这不是正确的方法。我理解这是因为它确实违背了课堂的要点。
我的程序从字符串文件中逐字逐句地读取,并检查每个单词是否都在数据库中。我想把找不到的每个单词都放在表单上的ListBox中,它可以有多个选项。
每次发现新单词时,我如何将数据发送回表单?
前几天,我问如何在课堂上创建一个消息框,但其中一个答案是这不是正确的方法。我理解这是因为它确实违背了课堂的要点。
我的程序从字符串文件中逐字逐句地读取,并检查每个单词是否都在数据库中。我想把找不到的每个单词都放在表单上的ListBox中,它可以有多个选项。
每次发现新单词时,我如何将数据发送回表单?
我建议你做一个这样的方法:
/* ... */
public IEnumerable<string> FindMissingWords(
string fileName, IEnumerable<string> toSearch)
{
List<string> missingWords = new List<string>();
// todo: the appropriate code for looking up strings in the file, using
// the filename and the strings that we passed into the function.
// if you find one, add it to missingWords
return missingWords;
}
然后从表单中调用该方法,并将它返回的每个字符串添加到框中。
(如果您不熟悉IEnumerable
,请不要担心,它只是一个定义一系列事物的接口,比如数组或列表。您可以传递一个字符串数组,但精度会稍低。)
如果类有对表单的引用,则它可以直接更新表单。
someForm.SomeListBox.Items.Add(someWord);
如果表单引用了类,则可以让类引发一个事件,如
public delegate string WordNotFoundHandler(string word);
public WordNotFoundHandler event WordNotFound ;
并让表单处理该事件
theClass.WordNotFound += AddItemToListBox
void AddItemToListBox(string word)
{
someListBox.Items.Add(word);
}
这样做的好处是,它提供了更快的ui响应时间,尤其是当由单独的线程完成时,而不是一个返回所有单词的巨大调用
这是我要做的(或类似的):
bool done = false;
while(true)
{
string foundstring;
done = searchforstring(out foundstring);
if(done)
break;
// Not done, so take what we found and add it to the listbox
this.BeginInvoke(new Action<string>(delegate(string input)
{ this.listBox.BeginUpdate(); this.listBox.Items.Add(input); this.listBox.EndUpdate(); }),
new object[] { foundstring });
}
用你的列表框控件的名称代替,我认为这会起作用。或者,您可以将匿名方法分解为自己的对象。其想法是,每次找到新字符串时,都会派遣一个工作线程在“主应用程序线程”中执行更新(因此调用BeginInvoke())。如果begin/endUpdate()调用是绝对必要的,我不会完全起诉,但它们可能是必要的。
显然,如何获取字符串取决于您自己,但假设您的应用程序是多线程的,那么这应该是将字符串快速放入列表框的方法。如果它不是多线程的,那么直接调用()(而不是BeginInvoke)应该可以立即更新列表框,但这可能会降低搜索性能。
You do not want to couple your form with the class that searches and find words from a file.
Here is an Event-based solution
Basically what you have to do is to expose an event in the class that reads and find words from a file (I named it as WordFinder
for an illustration.)
WordFinder
exposes an event called WordFound
that is raised when a new word is found.
public class WordFinder
{
public event EventHandler<WordFoundEventHandler> WordFound = delegate { };
public event EventHandler NoWordsFound = delegate { };
protected virtual void OnWordFound(WordFoundEventHandler e)
{
var wordFoundHandler = WordFound;
wordFoundHandler(this, e);
}
private void OnNoWordsFound(EventArgs e)
{
var noWordsFoundHandler = NoWordsFound;
noWordsFoundHandler(this, e);
}
public void FindWords(string fileName)
{
//.. read file and find word
//.. When a word is found,
OnWordFound(new WordFoundEventHandler(foundWord));
// Keep a counter somewhere and check if any words has been found,
// if no words are found, then raise "NoWordsFoundEvent"
OnNoWordsFound(EventArgs.Empty);
}
}
public class WordFoundEventHandler : EventArgs
{
public string FoundWord { get; private set; }
public WordFoundEventHandler(string foundWord)
{
FoundWord = foundWord;
}
}
现在,您的表单只需注册WordFinder
的事件,并在找到新单词时添加一个新项目。
public partial class Form1 : Form
{
private readonly WordFinder _WordFinder;
public Form1()
{
InitializeComponent();
_WordFinder = new WordFinder();
_WordFinder.WordFound += WordFinder_WordFound;
_WordFinder.NoWordsFound += WordFinder_NoWordsFound;
}
private void WordFinder_WordFound(object sender, WordFoundEventHandler e)
{
// Add item to the list here.
foundWordsListBox.Items.Add(e.FoundWord);
}
private void WordFinder_NoWordsFound(object sender, EventArgs e)
{
MessageBox.Show("No words found!");
}
private void findWordsButton_Click(object sender, EventArgs e)
{
_WordFinder.FindWords(/* pass file name here */);
}
}