我正在使用 BackgroundWorker 并在其中使用 foreach 循环,在其中我创建新线程,等待它完成,然后报告进度并继续 foreach 循环。这就是我要说的:
private void DoWork(object sender, DoWorkEventArgs e) {
var fileCounter = Convert.ToDecimal(fileNames.Count());
decimal i = 0;
foreach (var file in fileNames) {
i++;
var generator = new Generator(assembly);
var thread = new Thread(new ThreadStart(
delegate() {
generator.Generate(file);
}));
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
while (thread.IsAlive); // critical point
int progress = Convert.ToInt32(Math.Round(i / fileCounter * 100));
backgroundWorker.ReportProgress(progress);
}
}
Run Code Online (Sandbox Code Playgroud)
问题是线程完成后(通过“临界点”线后)内存没有被释放。我认为当线程不活动时,与它相关的所有资源都会被释放。但显然这不是真的。任何人都可以向我解释为什么以及我做错了什么。谢谢。
经过2个小时的研究,我仍然找不到解决我的问题的方法。
我所做的任务是在 BackGroundWorker 线程中处理一些文件。但是,有时我需要使用 ShowDialog 让用户选择 SaveFile 位置,但我收到 STA/MTA 错误。
主窗体代码:
private void button2_Click(object sender, EventArgs e)
{
button1.Enabled = false;
ProcessReportWorker.RunWorkerAsync();
}
Run Code Online (Sandbox Code Playgroud)
工作代码:
void ProcessReportWorker_DoWork(object sender, DoWorkEventArgs e)
{
int ReportCount = Reports.Count();
foreach (string Report in Reports)
{
ProcessReport NewReport = new ProcessReport(Report);
string result = NewReport.Start();
}
}
Run Code Online (Sandbox Code Playgroud)
ProcessReport.Start() 代码:
class ProcessReport
{
public string Start()
{
if(File.Exists(ResultPath))
{
SaveFileDialog SaveReport = new SaveFileDialog();
SaveReport.InitialDirectory = "c:\somepath";
SaveReport.CheckPathExists = true;
SaveReport.DefaultExt = ".xls";
SaveReport.OverwritePrompt = true;
SaveReport.ValidateNames …Run Code Online (Sandbox Code Playgroud) 我有一个ShowPanel(Control ctrl)需要Control作为参数传递的函数。我需要在后台工作线程中调用这个函数。我使用以下代码
void bw_DoWork(object sender,DoWorkEventArgs e)
{
ShowPanel(listBox1);
}
Run Code Online (Sandbox Code Playgroud)
但因执行而失败
跨线程操作无效:从创建它的线程以外的线程访问控件“Form1”
我怎样才能listBox1在后台线程中通过这里?
让我用一些背景信息来设置这个问题,我们有一个长时间运行的进程,它将在 Windows 窗体中生成数据。因此,显然需要某种形式的多线程来保持表单响应。但是,我们还要求表单每秒更新多次,同时仍然保持响应。
这是一个使用后台工作线程的简单测试示例:
void bw_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
int reportValue = (int)e.UserState;
label1.Text = reportValue;
//We can put this.Refresh() here to force repaint which gives us high repaints but we lose
//all other responsiveness with the control
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
for (int x = 0; x < 100000; x++)
{
//We could put Thread.Sleep here but we won't get highest performance updates
bw.ReportProgress(0, x);
}
}
Run Code Online (Sandbox Code Playgroud)
请查看代码中的注释。另外,请不要问我为什么要这个。问题很简单,我们如何在保持响应性的同时在更新表单时实现最高保真度(最多重绘)?强制重绘确实为我们提供了更新,但我们不处理 Windows 消息。
我也尝试放置 DoEvents,但这会产生堆栈溢出。我需要的是某种说法,“如果您最近没有处理任何 Windows 消息”。我也可以看到,可能需要稍微不同的模式来实现这一点。
看来我们需要处理几个问题: …
multithreading backgroundworker winforms task-parallel-library
我想更改 Backgroundworker 中数据网格的标签和背景。我有这样的网格:
<Grid HorizontalAlignment="Center" Height="499" Margin="96,170,810,0" VerticalAlignment="Top" Width="486" Background="{Binding aBackGround}">
<Label Content="212" FontSize="100" HorizontalAlignment="Left" VerticalAlignment="Top" RenderTransformOrigin="-4.395,-11.154" Margin="173,22,0,0" Height="123" Width="178"/>
<Label Content="{Binding aPace}" FontSize="65" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="23,202,0,0" Height="84" Width="255"/>
</Grid>
Run Code Online (Sandbox Code Playgroud)
在后面的代码中,我有 aBackGround 和 aPace,如下所示:
private Brush _aBackGround;
private string _apace;
public Brush aBackGround
{
get { return _aBackGround; }
set
{
_aBackGround= value;
RaisePropertyChanged(() => this.aBackGround);
}
}
public string aPace
{
get { return _apace; }
set
{
_apace = value;
RaisePropertyChanged(() => this.aPace);
}
}
Run Code Online (Sandbox Code Playgroud)
我可以正确地看到 aPace 的结果,但一秒钟后我得到 …
当我使用WinForms时,我会在我的bg_DoWork方法中完成这个:
status.Invoke(new Action(() => { status.Content = e.ToString(); }));
status.Invoke(new Action(() => { status.Refresh(); }));
Run Code Online (Sandbox Code Playgroud)
但是在我的WPF应用程序中,我得到一个错误,Invoke说不存在Label.
任何帮助,将不胜感激.
我正在尝试显示标签中后台工作人员的进度百分比值。我正在添加 Aprox。数据表 25 K 行。当我仅将 Label.Text 设置为 e.ProgressPercentage 时,它工作正常。但是当我计算%值时,它保持不变。只有在worker完成后标签才更新为100%
progressCount = report.Rows.Count;
foreach (DataRow r in report.Rows)
{
rp.pName = r[1].ToString();
rp.batch = r[2].ToString();
rp.expr = r[3].ToString();
rp.stock = r[5].ToString();
rp.rate = r[6].ToString();
backgroundWorker2.ReportProgress(i, rp);
System.Threading.Thread.Sleep(2);
if(backgroundWorker2.CancellationPending)
{
e.Cancel = true;
backgroundWorker2.ReportProgress(0);
}
i++;
}
private void backgroundWorker2_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
metroProgressBar1.Minimum = 0;
metroProgressBar1.Maximum = progressCount;
stock st = new stock();
reportClass rp = (reportClass)e.UserState;
if(!backgroundWorker2.CancellationPending)
{
st.stockReport.Rows.Add(rp.pName, rp.batch, rp.expr, rp.stock, rp.rate);
metroProgressBar1.Value = e.ProgressPercentage;
int percn = …Run Code Online (Sandbox Code Playgroud) 根据我读过的有关 QueueBackgroundWorkItem 的文献,我应该能够在后台完成一个长时间的任务而不会被 IIS 中断。
我想知道是否有可能,如果我开始一个很长的任务并在它完成之前关闭我的网站,QueueBackgroundWorkItem 不应该完成任务吗?(目前不是)
这是我的电话:
private async Task WriteTextAsync(CancellationToken cancellationToken)
{
string filePath = printPath;
string text;
byte[] encodedText = Encoding.Unicode.GetBytes(text);
for (int i = 0; i < 200; i++)
{
text = "Line " + i + "\r\n";
encodedText = Encoding.Unicode.GetBytes(text);
using (FileStream sourceStream = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
{
await sourceStream.WriteAsync(encodedText, 0, encodedText.Length);
};
Thread.Sleep(200);
}
}
private void QueueWorkItem()
{
Func<CancellationToken, Task> workItem = WriteTextAsync;
HostingEnvironment.QueueBackgroundWorkItem(workItem);
}
Run Code Online (Sandbox Code Playgroud)
编辑:我已经得到了这个工作。我修剪了它。现在在浏览器关闭后执行,大约 3-4 …
我对这一切都有些困惑。我需要在我的应用程序中创建一个生命周期方法,它将与 asp net web 服务进行通信,并返回一些结果。只要我的应用程序在运行,这个方法就永远不会停止。
t=Task.Run(()=>ffAsync());
async void ffAsync()
{
while (true)
{
await Task.Delay(5000);
Console.WriteLine("Reading from server every 5 seconds");
}
}
Run Code Online (Sandbox Code Playgroud)
Timer t = new Timer();
t.Interval = 5000;
timer1.Enabled = true;
timer1.Tick += new
System.EventHandler(OnTimerEvent);
private void OnTimerEvent(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
Run Code Online (Sandbox Code Playgroud)
方法 3 使用线程
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
while(true)
{
Thread.Sleep(5000);
Console.WriteLine("Run every 5 seconds");
}
}).Start();
Run Code Online (Sandbox Code Playgroud)
在我的情况下哪种方法更有效?还有另一个优化问题,最好使用 task.delay(x),Thread.Sleep(x) 每 x 秒运行一次我的循环,还是创建一个计时器(如我的秒示例),它会每 x 触发一次我的事件秒?
我有一个关于 invoke 用法的一般问题。我的大多数 C# winforms 项目都有一个后台工作人员和一个 UI。很快我意识到我需要来自后台工作人员 UI 的信息,或者我需要更改我的后台工作人员的 UI。例子:
//example invoke usage to get information from UI (dateMatch = CheckBox, fromDate&toDate = Datepicker)
bool isDateMatch = false;
dateMatch.Invoke(new MethodInvoker(delegate { isDateMatch = dateMatch.Checked; }));
DateTime fromDt = new DateTime();
fromDate.Invoke(new MethodInvoker(delegate { fromDt = fromDate.Value; }));
DateTime toDt = new DateTime();
toDate.Invoke(new MethodInvoker(delegate { toDt = toDate.Value; }));
Run Code Online (Sandbox Code Playgroud)
//example invoke usage to change UI (statusTxt = TextBox, progressBar = ProgressBar)
private void changeStatus(string statusTextV, bool enableProgressBar)
{
statusTxt.Invoke(new MethodInvoker(delegate …Run Code Online (Sandbox Code Playgroud) backgroundworker ×10
c# ×9
winforms ×3
wpf ×2
asp.net-mvc ×1
iis ×1
invoke ×1
showdialog ×1
sta ×1
task ×1
xaml ×1