控件 '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
实例,然后将同一对象传递给使用它的每个其他函数。这样可以保证整个过程访问的是同一个线程中的同一个对象。
我正在使用 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
实例,然后将同一对象传递给使用它的每个其他函数。这样可以保证整个过程访问的是同一个线程中的同一个对象。