我需要在单独的线程中调用类方法。该方法有一个参数和一个返回值。
详情
我有一个带有两个TextBox的表单。用户将值放在第一个TextBox中,并将结果输入第二个TextBox:
private void tbWord_TextChanged(object sender, TextChangedEventArgs e)
{
tbResponce.Text = Wiki.DoWork(tbWord.Text);
}
Wiki-class必须使用Wikipedia API:
public class Wiki
{
private class State
{
public EventWaitHandle eventWaitHandle = new ManualResetEvent(false);
public String result;
public String word;
}
private static void PerformUserWorkItem( Object stateObject )
{
State state = stateObject as State;
if(state != null)
{
Uri address = new Uri("http://en.wikipedia.org/w/api.php?action=opensearch&search=" + state.word);
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
HttpWebResponse responce = (HttpWebResponse)request.GetResponse();
StreamReader myStreamReader = new StreamReader(responce.GetResponseStream(), Encoding.GetEncoding(1251));
state.result = myStreamReader.ReadToEnd();
state.eventWaitHandle.Set();
}
}
public static String DoWork(String _word)
{
State state = new State();
state.word = _word;
ThreadPool.QueueUserWorkItem(PerformUserWorkItem, state);
state.eventWaitHandle.WaitOne();
return state.result;
}
}
问题
当用户在tbWord中按键时,主表单会冻结并等待Wiki类完成所有工作。
如何异步运行DoWork?
答案 0 :(得分:10)
或者像这样使用TPL:
private void tbWord_TextChanged(object sender, TextChangedEventArgs e)
{
Task.Factory.StartNew(() =>
{
return Wiki.DoWrok(tbWord.Text);
}).ContinueWith(taskState =>
{
tbResponce.Text = taskState.Result;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
答案 1 :(得分:2)
使用BackgroundWorker
课程。这将允许您异步运行您的操作。然后,当BackgroundWorker
通知它已完成操作时,您可以在Dispatcher线程上更新UI。
答案 2 :(得分:1)
另请参阅HttpWebRequest.BeginGetResponse以及有关如何异步执行Web请求的相关方法。这将消除任何自定义后台处理的需要。
答案 3 :(得分:0)
Youc可以使用WPF Dispatcher在主UI线程中执行操作,因为您已在WaitOne()
中使用DoWork
- 主DoWork操作将是同步的,因此您可以使用Dispatcher.BeginInvoke()
来推送UI线程异步更改:
Dispatcher.CurrentDispatcher.BeginInvoke(
DispatcherPriority.Input,
new ThreadStart(() =>
{
tbResponce.Text = Wiki.DoWork(tbWord.Text);
}));
请告诉我,这是否适合您,因为Polity提到了一些可能的同步问题
答案 4 :(得分:0)
不要等待ThreadPool
线程在UI线程中完成,而是订阅完整的事件:
class Program
{
static void Main(string[] args)
{
var program = new Program();
program.DoWorkComplete += (s, e) => Console.WriteLine(e.Result);
program.DoWorkAsync();
// Wait 10 seconds, worker thread should finish beforehand, so
// you see console output
Thread.Sleep(10000);
}
public event EventHandler<CompleteEventArgs> DoWorkComplete;
public void DoWorkAsync()
{
ThreadPool.QueueUserWorkItem(o =>
{
// Download data here
string result = "Result from Wiki";
if(DoWorkComplete != null)
DoWorkComplete(this, new CompleteEventArgs(result));
});
}
public class CompleteEventArgs : EventArgs
{
public CompleteEventArgs(string result)
{
this.Result = result;
}
public string Result { get; private set; }
}
}
编辑:这是一个控制台应用程序。我可以从任何线程WriteLine
。如果您正在使用WPF,则需要使用Dispatcher
来确保在UI线程(sll already stated)中处理DoWorkComplete
事件。如果您使用的是Windows窗体,则必须对Control.Invoke
执行相同的操作。
答案 5 :(得分:0)
您可以使用异步调用来实现这一点,