c#线程位图

本文关键字:位图 线程 | 更新日期: 2023-09-27 18:04:14

我想知道如果不是线程中的void函数,我可以传递位图函数。当我传递无效函数时,没有错误报告,但当我传递位图函数时,我得到一个错误。下面是代码:

protected void btnSubmit_Click(object sender, EventArgs e)
{  
Thread thr = new Thread(new ThreadStart(OptimizeWebBrowser));
thr.SetApartmentState(ApartmentState.STA);
thr.Start();       
}
public System.Drawing.Bitmap CaptureWebPage(string url)
{
System.Windows.Forms.WebBrowser browser = new System.Windows.Forms.WebBrowser();   
browser.ScrollBarsEnabled = false;
browser.ScriptErrorsSuppressed = true;
browser.Navigate(url);
while (browser.ReadyState != WebBrowserReadyState.Complete)
    System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(1500);
int width = browser.Document.Body.ScrollRectangle.Width;
int height = browser.Document.Body.ScrollRectangle.Height;
browser.Width = width;
browser.Height = height;
System.Drawing.Bitmap bmp = new Bitmap(width, height);
browser.DrawToBitmap(bmp, new System.Drawing.Rectangle(0, 0, width, height));
    return bmp;
}
protected void OptimizeWebBrowser()
{
    System.Windows.Forms.WebBrowser browser = new System.Windows.Forms.WebBrowser();
browser.ScrollBarsEnabled = false;
browser.ScriptErrorsSuppressed = true;
browser.Navigate(currentPageUrl);
while (browser.ReadyState != WebBrowserReadyState.Complete)
    System.Windows.Forms.Application.DoEvents();
System.Threading.Thread.Sleep(1500);
int width = browser.Document.Body.ScrollRectangle.Width;
int height = browser.Document.Body.ScrollRectangle.Height;
browser.Width = width;
browser.Height = height;
System.Drawing.Bitmap bmp = new Bitmap(width, height);
browser.DrawToBitmap(bmp, new System.Drawing.Rectangle(0, 0, width, height));
 Response.ContentType = "image/jpeg";
Response.AppendHeader("Content-Disposition", "attachment; filename=screenshot.jpg");
bmp.Save(Response.OutputStream, ImageFormat.Jpeg);
bmp.Dispose();
bmp.Dispose();
Response.End();     
}

当我现在试图把capture网页而不是OptimizeWebBrowser在ThreadStart,我得到一个错误:'没有超载' capture网页'匹配委托'System.Threading.ThreadStart'。

c#线程位图

要将参数传递给线程,您应该使用ParameterizedThreadStart委托,该委托具有object类型的单个参数。所以你应该像下面这样使用它:

System.Drawing.Bitmap bitmapObject;
private static readonly bitmapLock = new object();
// change parameter type to object and int he method just cast it to string
public void CaptureWebPage(object rawUrl) 
{
   string url = rawUrl.ToString();
   lock(bitmapLock)
   {
      // create a bitmap object
      bitmapObject = ...;
   }
}
// start thread
Thread thr = new Thread(CaptureWebPage); 
thr.Start("url");

PS:你发布的代码很难阅读,考虑一些代码重构和样式更改

还没有机会尝试这个,但是out关键字可能有效。将位图设置为函数的参数(将其保持为void函数),并在使用ParameterizedThreadStart创建threadstart时传递一个。由于out关键字在函数声明中,当函数完成时将返回该值。

如果不是,我建议你输出的位图是一个全局变量,你可以从任何一个线程访问。您可以像往常一样访问它,但我建议使用lock()关键字以防万一。

此外,c#中的BackgroundWorker类允许您在线程完成时通过向RunWorkerCompleted事件添加一个函数来获得返回结果

不行,不能传递有返回值的方法。由于ThreadStart方法不等待线程完成,因此从线程返回任何东西都没有意义,因为没有任何东西等待结果。

从线程返回数据有几种方法,例如在声明方法的类中使用成员变量,但棘手的部分是,在启动线程后不会立即获得结果,因此必须等待它。通常你会使用回调方法,当数据准备好使用时线程可以调用。

请注意,您的代码将永远不能可靠地工作,因为响应可能在您的代码完成之前结束(这称为竞争条件)。你应该研究一下IAsyncHttpHandler的用法。

但是,为了将来的参考,如果没有竞争条件,这就是如何解决这个问题的。

你需要使用上下文对象。首先,您需要声明一个类,其中包含该方法所需的所有信息(以及它的返回值,或者更理想的是,当结果准备好时要做的事情——也就是委托)。例如:

class CaptureWebPageContext
{
    public string Url;
    public Action<Bitmap> ResultDelegate;
}

一旦你有了这个,你可以初始化它并将它发送给void (object)委托(ParameterizedThreadStart):

var context = new CaptureWebPageContext() { Url = url, ResultDelegate = BitmapRendered };
var thr = new Thread(context);
thr.Start(context);
protected void BitmapRendered(Bitmap result)
{
    // ... Do stuff with the final bitmap.
}    
protected void CaptureWebPage(object contextObject)
{
    var context = (CaptureWebPageContext)contextObject;
    var url = context.Url;
    //... Your code to capture the web page.
    context.ResultDelegate(bmp);
    bmp.Dispose();
}

理想情况下,你会使用。net异步模式,但我看到你需要一个STA线程