控件 'ZedGraphControl' 从创建它的线程以外的线程访问

Control 'ZedGraphControl' accessed from a thread other than the thread it was created on

我正在使用 ZedGraph 库,但在网站上而不是 Web 窗体应用程序上。快速介绍 - 该应用程序从数据库中获取数据,生成图表,将其保存为图像,然后在网页上显示图像。

我有一个 GraphController class,它基本上是这样的:

public class GraphController {

    private static GraphController instance;
    private static ZedGraph.ZedGraphControl graph;
    protected GraphController() { }

    public static GraphController Instance {
        get {
            if (instance == null){
                instance = new GraphController();
            }
            return instance;
        }
    }

    public string GenerateGraph(Dictionary<DateTime, float> graphData, DataRow details, string graphType) {
        if ((graph == null) || (graph.IsDisposed == false)) {
            graph = new ZedGraph.ZedGraphControl();
        }
        graph.GraphPane.Title.IsVisible = false;
        // function calls to generate graph. Graph object is referenced in these.
        return SaveGraphAsImage(0000, graphType);
    }

    private void AddGridLines() {
        // example of graph reference
        graph.GraphPane.XAxis.MajorGrid.IsVisible = true;
    }

    private string SaveGraphAsImage(string paramId, string graphType) {
        // Should deal with save location here 
        string location = HttpRuntime.AppDomainAppPath + "Graphs\" + DateTime.Now.ToString("dd-MM-yyyy");
        string filename = DateTime.Now.ToString("dd-MM-yyyy-HH-mm-ss-") + graphType + "-" + paramId + ".png";

        if(System.IO.Directory.Exists(location) == false){
            System.IO.Directory.CreateDirectory(location);
        }
        graph.Refresh();

        try {
            using (graph) {
                string outputFileName = location + "\" + filename;

                if (File.Exists(outputFileName) == false) {
                    Bitmap image = graph.GraphPane.GetImage(960, 660, 180);
                    image.Save(outputFileName, ImageFormat.Png);
                    image.Dispose();
                }
            }
            graph = null; // double check that it is removed.
            return "../Graphs/" + DateTime.Now.ToString("dd-MM-yyyy") + "/" + filename;
        }
        catch (Exception ex) {
            log("An error occured generating a graph. \n\n Error message: \n " + ex.Message + " \n\n Stack trace: \n " + ex.StackTrace);
            graph = null;
            return "#";
        }
    }
}

我已经尽可能地减少了它,但它应该显示 ZedGraph 对象是如何创建、使用和删除的。

我已经尝试了一些内存增强功能,尽可能删除图形对象,并尝试 using(){} 过程以希望自动删除它,但欢迎进一步的建议。

我的目标是改进内存管理并减少这些错误。 运行 本地性能测试,我遇到了很多 Control 'ZedGraphControl' accessed from a thread other than the thread it was created on. 错误。我对线程比较陌生,所以我不确定 a) 是否需要它,或者 b) 可以做些什么来禁用这种可能性,或者更好地管理图形对象以确保它总是在同一个线程中?

Edit:此 GraphController 首先从 .aspx.cs 页面调用,具有以下内容:GraphController.GraphController.Instance.GenerateGraph(data, details, "graph-type");

第二次编辑:我重写了代码,使 ZedGraphControl 没有 private static,而是在 GenerateGraph 和然后在必要的地方传递。在 60 秒内对多达 1,000 名用户进行测试,看起来已经消除了跨线程问题 - 这听起来可能吗?

这里的问题是 static 变量的使用。正如 Henk Holterman 在评论中指出的那样,只要应用程序进程处于活动状态,静态变量就会保持活动状态,并且与 any/all 用户请求分开。因此,通过将 ZedGraph 对象作为 static 变量,这并不意味着它可能仍然可用于多个请求而没有被正确清除,运行 进入内存和跨线程问题。

解决方案是在第一个 GenerateGraph 函数中声明 ZedGraph 实例,然后将同一对象传递给使用它的每个其他函数。这样可以保证整个过程访问的是同一个线程中的同一个对象。