我正在尝试创建一个应定期连接到服务器并从中请求字符串的应用程序。这应该在后台完成,以免在尝试连接时冻结UI。为了实现这一点,我试图使用System.Timers.Timer类。但是,从不调用BackgroundConnect_DoWork。
为了测试BackgroundWorker的概念,我向应用程序添加了一个按钮,该按钮可以正常工作。按下时将触发BackgroundConnect_DoWork。
public partial class MainWindow : Window
{
private BackgroundWorker backgroundConnect = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
backgroundConnect = ((BackgroundWorker)this.FindResource("BackgroundConnect"));
Timer reconnectTimer = new Timer();
reconnectTimer.Interval = 500; //Twice per second
reconnectTimer.Elapsed += ReconnectTimer_Elapsed;
reconnectTimer.Enabled = true;
}
private void ReconnectTimer_Elapsed(object sender, ElapsedEventArgs e)
{
/*IPInput and PortInput are names of corresponding textboxes*/
string InputHost = IPInput.Text;
int InputPort = int.Parse(PortInput.Text);
IPEndPoint InputIPEndpoit = IpTools.GetIPEndPointFromHostName(InputHost, InputPort); //That's working OK when tested separately
backgroundConnect.DoWork += BackgroundConnect_DoWork;
backgroundConnect.RunWorkerCompleted += BackgroundConnect_RunWorkerCompleted;
backgroundConnect.RunWorkerAsync(InputIPEndpoit);
}
/* Handler for clicking of ConnectNow button */
private void ConnectNow_MouseUp(object sender, MouseButtonEventArgs e)
{
string InputHost = IPInput.Text;
int InputPort = int.Parse(PortInput.Text);
IPEndPoint InputIPEndpoit = IpTools.GetIPEndPointFromHostName(InputHost, InputPort);
backgroundConnect.RunWorkerAsync(InputIPEndpoit); //This one is executed correctly when button is clicked
}
/*Works OK on button click*/
private void BackgroundConnect_DoWork(object sender, DoWorkEventArgs e)
{
IPEndPoint InputIPEndpoit = (IPEndPoint)e.Argument;
e.Result = SemTCPCommandClient.SendReceiveCommand(InputIPEndpoit, Settings.Default.StringToMicroscopeTM4000);
}
private void BackgroundConnect_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Some UI update
}
}
答案 0 :(得分:0)
解决方案:
public partial class MainWindow : Window
{
private BackgroundWorker backgroundConnect = new BackgroundWorker();
public MainWindow()
{
InitializeComponent();
backgroundConnect = ((BackgroundWorker)this.FindResource("BackgroundConnect"));
DispatcherTimer reconnectTimer = new DispatcherTimer();
reconnectTimer.Interval = TimeSpan.FromMilliseconds(500); //Twice per second
reconnectTimer.Tick += ReconnectTimer_Tick;
reconnectTimer.Start();
}
private void ReconnectTimer_Tick(object sender, EventArgs e)
{
/*IPInput and PortInput are names of corresponding textboxes*/
string InputHost = IPInput.Text;
int InputPort = int.Parse(PortInput.Text);
IPEndPoint InputIPEndpoit = IpTools.GetIPEndPointFromHostName(InputHost, InputPort); //That's working OK when tested separately
//If below is not commented, than BackgroundConnect_DoWork is executed multiple times on each Timer_Tick
//backgroundConnect.DoWork += BackgroundConnect_DoWork;
//backgroundConnect.RunWorkerCompleted += BackgroundConnect_RunWorkerCompleted;
if (backgroundConnect.IsBusy == false) //In order not to call async twice, or it will throw an exception
backgroundConnect.RunWorkerAsync(InputIPEndpoit);
}
/* Handler for clicking of ConnectNow button */
private void ConnectNow_MouseUp(object sender, MouseButtonEventArgs e)
{
string InputHost = IPInput.Text;
int InputPort = int.Parse(PortInput.Text);
IPEndPoint InputIPEndpoit = IpTools.GetIPEndPointFromHostName(InputHost, InputPort);
backgroundConnect.RunWorkerAsync(InputIPEndpoit); //This one is executed correctly when button is clicked
}
/*Works OK on button click*/
private void BackgroundConnect_DoWork(object sender, DoWorkEventArgs e)
{
IPEndPoint InputIPEndpoit = (IPEndPoint)e.Argument;
e.Result = SemTCPCommandClient.SendReceiveCommand(InputIPEndpoit, Settings.Default.StringToMicroscopeTM4000);
}
private void BackgroundConnect_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
//Some UI update
}
}
想法是DispatcherTimer可以在UI上运行,而System.Timer.Timer不能。一些讨论可以在这里找到: https://social.msdn.microsoft.com/Forums/en-US/77909245-0ecd-4fbd-b831-d82dd6f6edd1/what-is-difference-between-timer-and-dispatcher-timer-?forum=csharplanguage
答案 1 :(得分:0)
您仍然必须将要注册到DoWork
和RunWorkerCompleted
事件的行从ReconnectTimer_Tick
方法移动到构造函数。
如果您尝试将时间跨度设置为3000,并在BackgroundConnect_RunWorkerCompleted
中设置一个断点,则您会看到当前在第一次运行后调用一次,第二次运行后调用两次,依此类推。
第backgroundConnect = ((BackgroundWorker)this.FindResource("BackgroundConnect"));
行做什么?我想你可以把它省略掉。
如果不是您的MainWindow
,则还应该编写一个Close
事件处理程序以停止计时器。
实际上,BackgroundWorker
是WPF最初的概念。您不再需要使用它,因为现在C#中内置了异步编程的更强大功能。它仍在工作,我只是想指出这一点。