C#OPC应用程序相同的代码,但工作方式不同

前端之家收集整理的这篇文章主要介绍了C#OPC应用程序相同的代码,但工作方式不同前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在开发一个C#定制OPC客户端,我开始在控制台应用程序中编写快速,一切都按照我想要的方式工作.

然后我决定制作一个视窗体验的Windows窗体应用程序.

Windows窗体应用程序只需停止工作,大约一分钟后停止从OPC服务器读取数据.控制台应用程序继续阅读和阅读的位置.

在调试模式下也找不到任何明显的东西.

我绝对在这里抓住稻草,希望有人可以散发光芒.

每个应用程序都使用OPCFoundation提供的.dll文件.

这是控制台应用程序

  1. static void Main(string[] args)
  2. {
  3.  
  4. Opc.URL url = new Opc.URL("opcda://localhost/RSLinx OPC Server");
  5. Opc.Da.Server server = null;
  6. OpcCom.Factory fact = new OpcCom.Factory();
  7. server = new Opc.Da.Server(fact,null);
  8. server.Connect(url,new Opc.ConnectData(new System.Net.NetworkCredential()));
  9. // Create a group
  10. Opc.Da.Subscription group;
  11. Opc.Da.SubscriptionState groupState = new Opc.Da.SubscriptionState();
  12. groupState.Name = "Group";
  13. groupState.Active = true;
  14. group = (Opc.Da.Subscription)server.CreateSubscription(groupState);
  15. // add items to the group.
  16. Opc.Da.Item[] items = new Opc.Da.Item[6];
  17. items[0] = new Opc.Da.Item();
  18. items[0].ItemName = "[UX1]F20:9";
  19. items[1] = new Opc.Da.Item();
  20. items[1].ItemName = "[UX1]F22:30";
  21. items[2] = new Opc.Da.Item();
  22. items[2].ItemName = "[UX1]F22:6";
  23. items[3] = new Opc.Da.Item();
  24. items[3].ItemName = "[UX1]F18:8";
  25. items[4] = new Opc.Da.Item();
  26. items[4].ItemName = "[UX1]F22:32";
  27. items[5] = new Opc.Da.Item();
  28. items[5].ItemName = "[UX1]F22:5";
  29. items = group.AddItems(items);
  30.  
  31. group.DataChanged += new Opc.Da.DataChangedEventHandler(OnTransactionCompleted);
  32.  
  33. }
  34.  
  35.  
  36.  
  37.  
  38.  
  39. static void OnTransactionCompleted(object group,object hReq,Opc.Da.ItemValueResult[] items)
  40. {
  41.  
  42. Console.WriteLine("------------------->");
  43. Console.WriteLine("DataChanged ...");
  44. for (int i = 0; i < items.GetLength(0); i++)
  45. {
  46.  
  47. Console.WriteLine("Item DataChange - ItemId: {0}",items[i].ItemName);
  48. Console.WriteLine(" Value: {0,-20}",items[i].Value);
  49. Console.WriteLine(" TimeStamp: {0:00}:{1:00}:{2:00}.{3:000}",items[i].Timestamp.Hour,items[i].Timestamp.Minute,items[i].Timestamp.Second,items[i].Timestamp.Millisecond);
  50.  
  51. }
  52. Console.WriteLine("-------------------<");
  53. }

这是WinForm应用程序

  1. public Form1()
  2.  
  3. {
  4. InitializeComponent();
  5. _Form1 = this;
  6. }
  7.  
  8. public static Form1 _Form1;
  9.  
  10. public void update(string message)
  11.  
  12. {
  13. this.richTextBox1.Text = message;
  14. }
  15.  
  16. private void Form1_Load(object sender,EventArgs e)
  17.  
  18. {
  19.  
  20. readplc();
  21.  
  22. }
  23.  
  24.  
  25. static void readplc()
  26. {
  27. Opc.URL url = new Opc.URL("opcda://localhost/RSLinx OPC Server");
  28. Opc.Da.Server server = null;
  29. OpcCom.Factory fact = new OpcCom.Factory();
  30. server = new Opc.Da.Server(fact,new Opc.ConnectData(new System.Net.NetworkCredential()));
  31. // Create a group
  32. Opc.Da.Subscription group;
  33. Opc.Da.SubscriptionState groupState = new Opc.Da.SubscriptionState();
  34. groupState.Name = "Group";
  35. groupState.Active = true;
  36. group = (Opc.Da.Subscription)server.CreateSubscription(groupState);
  37. // add items to the group.
  38. Opc.Da.Item[] items = new Opc.Da.Item[6];
  39. items[0] = new Opc.Da.Item();
  40. items[0].ItemName = "[UX1]F20:9";
  41. items[1] = new Opc.Da.Item();
  42. items[1].ItemName = "[UX1]F22:30";
  43. items[2] = new Opc.Da.Item();
  44. items[2].ItemName = "[UX1]F22:6";
  45. items[3] = new Opc.Da.Item();
  46. items[3].ItemName = "[UX1]F18:8";
  47. items[4] = new Opc.Da.Item();
  48. items[4].ItemName = "[UX1]F22:32";
  49. items[5] = new Opc.Da.Item();
  50. items[5].ItemName = "[UX1]F22:5";
  51. items = group.AddItems(items);
  52.  
  53.  
  54.  
  55. group.DataChanged += new Opc.Da.DataChangedEventHandler(OnTransactionCompleted);
  56.  
  57.  
  58. }
  59.  
  60.  
  61.  
  62.  
  63. static void OnTransactionCompleted(object group,Opc.Da.ItemValueResult[] items)
  64. {
  65.  
  66. for (int i = 0; i < items.GetLength(0); i++)
  67. {
  68.  
  69. UIUpdater TEXT = new UIUpdater();
  70. TEXT.UpdateText(items.GetLength(0).ToString() + " t " + i.ToString() + "Item DataChange - ItemId:" + items[i].ItemName +
  71. "Value: " + items[i].Value + " TimeStamp: " + items[i].Timestamp.Hour + ":" +
  72. items[i].Timestamp.Minute + ":" + items[i].Timestamp.Second + ":" + items[i].Timestamp.Millisecond);
  73.  
  74. }
  75.  
  76. }

UIUpdate类

  1. class UIUpdater
  2.  
  3. {
  4.  
  5. public void UpdateText(string DATA)
  6.  
  7. {
  8. Form1._Form1.update(DATA);
  9. }
  10.  
  11. public class UpdateUI
  12.  
  13. {
  14.  
  15.  
  16.  
  17. public int updatedRows { get; set; }
  18.  
  19. public string Custom1 { get; set; }
  20.  
  21. public string Custom2 { get; set; }
  22.  
  23. public string Custom3 { get; set; }
  24.  
  25. public string exception { get; set; }
  26.  
  27. public plcTextStatus PLCStatus { get; set; }
  28.  
  29.  
  30. }

任何问题请问!

解决方法

怀疑,这是一个跨线程问题.问题是你不能从UI线程的任何其他线程更新UI.完成事务的事件实际上在一个单独的线程上被调用,所以它更新了UI.

它工作一段时间,因为它相对容忍的错误,但你可能达到一个点,你是死锁或抛出一个没有被捕获(或报告)的异常.

修复很简单,但是.

在这种方法中:

  1. public void update(string message)
  2. {
  3. this.richTextBox1.Text = message;
  4. }

将其更改为:

  1. public void update(string message)
  2. {
  3. richTextBox1.Invoke(
  4. (MethodInvoker) delegate
  5. {
  6. richTextBox1.Text = message;
  7. });
  8. }

这样做是告诉richTextBox1“调用”或运行以下委托(函数)在它自己的线程(也就是UI线程)上.

您应该尽量避免在此代码中使用静态方法和引用.我没有看到你的代码不应该是实例方法而不是静态代码的任何原因.

作为附注,我编写了OPC程序,每秒处理数千个标签和数百个UI更新.你正在做的工作是为小型演示程序,但不会扩大很好.当架构越来越多时,您需要开始批量修改UI更新,因此您不会在更新中重复调用UI线程.

编辑

另一个问题是使用本地引用(例如,对于OPC服务器和订阅),并演示了内存泄漏和僵尸对象.发生了什么是readplc方法超出范围,您已经创建了对内存中保存的对象的引用.由于您无法取消订阅该活动,因此该活动将持续开放.这些变量应该声明在readplc方法的范围之外,所以您可以正确地取消订阅该事件并关闭OPC服务器.否则你正在离开僵尸订阅(看看RSLinx OPC诊断页面,你会看到所有你的订阅坐在那里).

猜你在找的C&C++相关文章