gpt4 book ai didi

c# - 在执行期间从 UI 向 BackgroundWorker 传递信息

转载 作者:行者123 更新时间:2023-11-30 12:14:01 27 4
gpt4 key购买 nike

我有一个使用后台工作线程的 c# 应用程序,并且非常成功地从正在运行的线程更新了 UI。该应用程序涉及网络上的最短路径路由,当后台工作人员继续进行时,我会在 UI 上显示网络和最短路径。我希望允许用户在应用程序运行时通过使用滑块来减慢显示速度。

我发现这是一个建议,但它在 vb.net 中,我不清楚如何让它在 c# 中工作。

How can the BackgroundWorker get values from the UI thread while it is running?

我可以将滑块的值传递给后台工作人员,如下所示:

//启动异步操作。
延迟 = this.trackBar1.Value;
backgroundWorker1.RunWorkerAsync(延迟);

并在后台工作线程中使用它,但它只使用最初发送的值。当我在 UI 上移动滑块时,我不清楚如何从后台工作人员内部获取值。

我以前使用过多个线程和委托(delegate),但如果可以使用后台工作程序,我更喜欢它的简单性。

5/10/2012

感谢大家的回应。我仍然有问题,很可能是因为我如何组织事物。网络路由的繁重计算是在 TransportationDelayModel 类中完成的。 BackgroundWorker_DoWork 创建此类的一个实例,然后将其启动。延迟在 TransportationDelayModel 中处理。

代码骨架如下:

在用户界面中:

 private void runToolStripMenuItem1_Click(object sender, EventArgs e)
{
if (sqliteFileName.Equals("Not Set"))
{
MessageBox.Show("Database Name Not Set");
this.chooseDatabaseToolStripMenuItem_Click(sender, e);

}

if (backgroundWorker1.IsBusy != true)
{
// Start the asynchronous operation.
delay = this.trackBar1.Value;
// pass the initial value of delay
backgroundWorker1.RunWorkerAsync(delay);
// preclude multiple runs
runToolStripMenuItem1.Enabled = false;
toolStripButton2.Enabled = false;
}

}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker worker = sender as BackgroundWorker;

if (!backgroundWorkerLaunched)
{
// instantiate the object that does all the heavy work
TransportationDelayModel TDM = new TransportationDelayModel(worker, e);
// kick it off
TDM.Run(sqliteFileName, worker, e);
backgroundWorkerLaunched = true;
}


}

TransportationDelayModel 构造函数是:
 public TransportationDelayModel(BackgroundWorker worker, DoWorkEventArgs e)
{
listCentroids = new List<RoadNode>();
listCentroidIDs = new List<int>();
listNodes = new List<RoadNode>();
listNodeIDs = new List<int>();
listRoadLink = new List<RoadLink>();
roadGraph = new AdjacencyGraph<int, RoadLink>(true); // note parallel edges allowed
tdmWorker = worker;
tdmEvent = e;
networkForm = new NetworkForm();
}

所以我有 tdmWorker,它允许我将信息传递回 UI。

在 TransportationDelayModel 的内部计算中,我睡了延迟期
  if (delay2 > 0)
{
tdmWorker.ReportProgress(-12, zzz);
System.Threading.Thread.Sleep(delay2);
}

所以问题似乎是如何将更新的滑块值从 UI 传递回在后台工作程序中执行的对象。我已经尝试了多种组合,有点颠簸,但无济于事,要么什么也没发生,要么我收到一条关于不允许访问另一个线程上发生的事情的消息。我意识到,如果我在 DoWork 事件处理程序中完成所有工作,那么我应该能够按照您的建议做事,但是要做到这一点太复杂了。

再次感谢您的建议和帮助。

6/2/2012

我已经通过两种方法解决了这个问题,但我还有一些问题。根据我对 R. Harvey 的评论,我构建了一个简单的应用程序。它由一个带有运行按钮的表单、一个滑块和一个富文本框组成。运行按钮启动一个后台工作线程,它实例化一个“模型”类的对象,该对象完成所有工作(我的 TransportationModel 的简化代理)。 Model 类只是将 100 行写入文本框,每行中的点数增加 1,每行之间的延迟基于滑块的设置,以及行尾的滑块值,类似于这个:

......................................58

......................................58

......................................58

......................................51

......................................44

......................................44

本练习的目标是能够在“模型”运行时移动表单上的滑块,并获得更改的延迟(如上所示)。

我的第一个解决方案涉及创建一个 Globals 类,以保存滑块的值:
class Globals
{
public static int globalDelay;
}

然后,在表单中,每当滚动轨迹栏时,我都会更新此值:
private void trackBar1_Scroll(object sender, EventArgs e)
{
Globals.globalDelay = this.trackBar1.Value;
}

而在模型中,我只是拿起了全局的值:
 public void Run(BackgroundWorker worker, DoWorkEventArgs e)
{

for (int i = 1; i < 100; i++)
{
delay = Globals.globalDelay; // revise delay based on static global set on UI
System.Threading.Thread.Sleep(delay);
worker.ReportProgress(i);
string reportString = ".";
for (int k = 0; k < i; k++)
{
reportString += ".";
}
reportString += delay.ToString();
worker.ReportProgress(-1, reportString);

}
}
}

这工作得很好。
我的问题:这种方法有什么缺点吗,它看起来很容易实现,而且很通用。

第二种方法基于 R. Harvey 的建议,利用委托(delegate)和调用。

我为代表创建了一个类:
 public class MyDelegates
{
public delegate int DelegateCheckTrackBarValue(); // create the delegate here
}

在表单中,我创建:
  public int CheckTrackBarValue()
{
return this.trackBar1.Value;

}

并且 Model 类现在有一个成员 m_CheckTrackBarValue
 public class Model 
{

#region Members

Form1 passedForm;
public static MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue=null;
#endregion Members

#region Constructor
public Model(BackgroundWorker worker, DoWorkEventArgs e, Form1 form)
{
passedForm = form;
}

当后台线程被运行按钮启动时,调用表单被传递

private void button1_Click(object sender, EventArgs e)
{
if (backgroundWorker1.IsBusy != true)
{
            backgroundWorker1.RunWorkerAsync();

}
}

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{

BackgroundWorker worker = sender as BackgroundWorker;

if (!backgroundWorkerLaunched)
{
// instantiate the object that does all the heavy work
Model myModel= new Model(worker, e, this);

Model.m_CheckTrackBarValue = new MyDelegates.DelegateCheckTrackBarValue(this.CheckTrackBarValue);

// kick it off
myModel.Run(worker, e);
backgroundWorkerLaunched = true;
}
}

最后在Model中,在传入的表单上调用Invoke方法来获取trackbar的值。
public void Run(BackgroundWorker worker, DoWorkEventArgs e)
{
     for (int i = 1; i < 100; i++)
{
int delay = (int)passedForm.Invoke(m_CheckTrackBarValue,null); // invoke the method, note need the cast here
System.Threading.Thread.Sleep(delay);
worker.ReportProgress(i);
string reportString = ".";
for (int k = 0; k < i; k++)
{
reportString += ".";
}
reportString += delay.ToString();
worker.ReportProgress(-1, reportString);

}
}

这也有效。我一直收到错误,直到我将成员变量设为静态,例如
公共(public)静态 MyDelegates.DelegateCheckTrackBarValue m_CheckTrackBarValue=null;

我对此解决方案的问题:与以前的版本相比,此解决方案有优势吗?我在实现这个的方式上是否让事情变得过于复杂?为什么 m_CheckTrackBarValue 需要是静态的。

对于这次编辑的长度,我深表歉意,但我认为其他人可能会对问题和解决方案感兴趣。

最佳答案

您必须通过 TrackBar反对 BackgroundWorker ,不是 delay . delay一旦设置就不会改变。

简化所需Invoke() ,您可以使用辅助方法,例如 this one :

Async.UI(delegate { textBox1.Text = "This is way easier!"; }, textBox1, true);

关于c# - 在执行期间从 UI 向 BackgroundWorker 传递信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10502451/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com