public TabTreeListView() { //Console.WriteLine("VarEnum.VT_ARRAY | VarEnum.VT_EMPTY is: " + (VarEnum.VT_ARRAY | VarEnum.VT_VARIANT)); //Console.WriteLine("typeof(System.Type).GetFields(BindingFlags.Public | BindingFlags.Static) is : " + (System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static)); CultureInfo culture = new CultureInfo("zh-CN"); // Saudi Arabia System.Threading.Thread.CurrentThread.CurrentCulture = culture; //CheckForIllegalCrossThreadCalls = false; InitializeComponent(); DllHelper.RegisterDllAndExe(); this.ListView = treeListView; //this.ListView.CellClick += (sender, args) => Debug.WriteLine("CellClicked: {0}", args); this.ListView.SelectionChanged += delegate(object sender, EventArgs args) { if (this.ListView.SelectedObject != null) { lastTag = (OPCTag)(this.ListView.SelectedObject); ShowTagProperties((OPCTag)(this.ListView.SelectedObject)); } }; createTagStructure(); opcClient = new OPCClient(); opcClient.AddTagsComplete += new EventHandler(OnAddTagsComplete); opcClient.GetAllTagNamesComplete += new EventHandler(OnGetAllTagNamesComplete); //opcClient.GetLocalServer(); }
/////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Writes the opc tag value to the server asyncronously /// </summary> /// <param name="tag"></param> /// <returns></returns> /////////////////////////////////////////////////////////////////////////////////////////// private void AsyncWrite(OPCTag tag) { try { Array serverErrors = default(Array); Array serverHandles = new int[2]; serverHandles.SetValue((int)tag.OPCItem.ServerHandle, 1); // 它的这个根据自己的DataType 来Write 数据的,我可以不必理会 //Array values = GetValue(tag); // 这是网上的一种写法 //object[] valueTemp = new object[2] {"",tag.Value }; //Array values=(Array)valueTemp; // 这是那个 OPCClient 的写法 Array values = new object[2]; values.SetValue(tag.Value, 1); int cancelID; int transID = GetNextTransID(); tag.OPCGroup.AsyncWrite(1, ref serverHandles, ref values, out serverErrors, transID, out cancelID); mAcyncWriteTags.Add(transID, tag); HandleServerError(serverErrors); } catch (Exception ex) { //Exception EVent } }
private void ShowTagPropertiesWorker(OPCTag tag) { //OPCTag tag = listView.SelectedObject as OPCTag; //OPCTag focusedTag = listView.FocusedObject as OPCTag; if (tag != null && tag.isRealTag) { if (tag.Value == null) { this.TagValueBox.Text = "<null>"; } else { this.TagValueBox.Text = tag.Value.ToString(); } this.TagQualityBox.Text = tag.QualityText; this.TagTimestampBox.Text = tag.ItemTimeStampText; } else if (tag != null && !tag.isRealTag) { this.TagValueBox.Text = ""; this.TagQualityBox.Text = ""; this.TagTimestampBox.Text = ""; } this.WriteValueInput.Text = ""; }
public void ReadPropertyValues(ref OPCTag tag) { // count 必须比 propIds.Length 少一个 int count = 4; List <int> propIds = new List <int>(); propIds.Add(0); propIds.Add(1); propIds.Add(2); propIds.Add(3); propIds.Add(4); Array PropertyIDs = propIds.ToArray(); Array PropertyValues; Array Errors; try{ mServer.GetItemProperties(tag.Name, count, ref PropertyIDs, out PropertyValues, out Errors); if ((count == 0) || (count > 10000)) { return; } for (int i = 1; i <= count; i++) { if (i == 1) { VarEnum dataType = (VarEnum)VarEnum.ToObject(typeof(VarEnum), PropertyValues.GetValue(i)); //tag.DataType = dataType; //var text = dataType.ToString(); // these methods are clunkier but run 25% faster on my machine var text2 = Enum.GetName(typeof(VarEnum), dataType); //var text3 = typeof(VarEnum).GetEnumName(dataType); tag.DataTypeText = text2; } else if (i == 2) { tag.SetValue(this, PropertyValues.GetValue(i)); } else if (i == 3) { tag.Quality = (OPCQuality)PropertyValues.GetValue(i); } else if (i == 4) { tag.ItemTimeStamp = (DateTime)PropertyValues.GetValue(i); } break; } } catch (Exception ex) { } }
public void OnTagValueUpdate(object sender, TagEventArgs e) { if (this.ListView.InvokeRequired) { //instansiate a delegate with the method OnTagValueUpdateDelegate myDelegate = new OnTagValueUpdateDelegate(OnTagValueUpdateWorker); //Invoke delegate this.ListView.Invoke(myDelegate, sender, e); } else { //Console.WriteLine("in OnTagValueUpdate 1"); // Server端的Value变了,treelistview 的回调函数 if (sender.Equals(opcClient)) { // 这里的 sender 到底是不是 opcclient 呢? try { OPCTag tag = keyTagMap[e.Tag.Name]; if (this.ListView.SelectedObject != null) { if (tag == (OPCTag)this.ListView.SelectedObject) { ShowTagProperties(tag); } } else if (lastTag != null) { if (tag == lastTag) { ShowTagProperties(tag); } } //this.treeListView.Refresh(); //this.treeListView.RefreshOverlays(); //this.treeListView.RefreshHotItem(); this.treeListView.Invalidate(); //if (tag.isFirstUpdate) //{ //tag.isFirstUpdate = false; ////opcClient.QueryAvailableProperties(tag.Name); ////opcClient.GetItemProperties(tag.Name); //} //Console.WriteLine("in OnTagValueUpdate, Name is: " + e.Tag.Name + ", Value is: " + e.Tag.Value); // 这里,应该让 TreeListView 刷新。 能不能做到单独刷新一个 元素呢? } catch (Exception ex) { //Error event } } //Console.WriteLine("in OnTagValueUpdate 2"); } }
/////////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Converts the tag value to an array for writing to the OPC Server /// </summary> /// <param name="tag"></param> /// <returns></returns> /////////////////////////////////////////////////////////////////////////////////////////////// private Array GetValue(OPCTag tag) { Array values = new object[2]; switch (tag.DataType) { case DataType.Bool: values.SetValue(Convert.ToBoolean(tag.Value), 1); break; case DataType.Byte: values.SetValue(Convert.ToByte(tag.Value), 1); break; case DataType.Int16: values.SetValue(Convert.ToInt16(tag.Value), 1); break; case DataType.Int32: values.SetValue(Convert.ToInt32(tag.Value), 1); break; case DataType.Int64: values.SetValue(Convert.ToInt64(tag.Value), 1); break; case DataType.UInt16: values.SetValue(Convert.ToUInt16(tag.Value), 1); break; case DataType.UInt32: values.SetValue(Convert.ToUInt32(tag.Value), 1); break; case DataType.UInt64: values.SetValue(Convert.ToUInt64(tag.Value), 1); break; case DataType.Real32: values.SetValue(Convert.ToSingle(tag.Value), 1); break; case DataType.Real64: values.SetValue(Convert.ToDouble(tag.Value), 1); break; case DataType.String: values.SetValue(Convert.ToString(tag.Value), 1); break; } return(values); }
/////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Writes the opc tag value to the server syncronously /// </summary> /// <param name="tag"></param> /// <returns></returns> /////////////////////////////////////////////////////////////////////////////////////////// private void SyncWrite(OPCTag tag) { try { Array serverErrors = default(Array); Array serverHandles = new int[2]; serverHandles.SetValue((int)tag.OPCItem.ServerHandle, 1); Array values = GetValue(tag); tag.OPCGroup.SyncWrite(1, ref serverHandles, ref values, out serverErrors); HandleServerError(serverErrors); } catch (Exception ex) { //Excpetion event } }
//private void comboBoxHotItemStyle_SelectedIndexChanged(object sender, EventArgs e) //{ //Coordinator.ChangeHotItemStyle(this.ListView, (ComboBox)sender); //} //private void buttonRefresh_Click(object sender, EventArgs e) //{ //this.treeListView.RefreshObjects(this.treeListView.SelectedObjects); //} //private void buttonCheck_Click(object sender, EventArgs e) { //this.treeListView.ToggleSelectedRowCheckBoxes(); //} //private void buttonSaveState_Click(object sender, EventArgs e) //{ //// SaveState() returns a byte array that holds the current state of the columns. //// For this demo, we just hold onto that value in an instance variable. For your //// application, you should persist it some more permanent fashion than this. //this.treeListViewViewState = this.treeListView.SaveState(); //this.buttonRestoreState.Enabled = true; //} //private void buttonRestoreState_Click(object sender, EventArgs e) //{ //this.treeListView.RestoreState(this.treeListViewViewState); //} //private void buttonColumns_Click(object sender, EventArgs e) //{ //ColumnSelectionForm form = new ColumnSelectionForm(); //form.OpenOn(this.treeListView); //} //private void buttonDisable_Click(object sender, EventArgs e) //{ //bool isControlKeyDown = ((Control.ModifierKeys & Keys.Control) == Keys.Control); //if (isControlKeyDown) //this.ListView.EnableObjects(this.ListView.DisabledObjects); //else //this.ListView.DisableObjects(this.ListView.SelectedObjects); //} #endregion //private void comboBoxExpanders_SelectedIndexChanged(object sender, EventArgs e) { //TreeListView.TreeRenderer treeColumnRenderer = this.treeListView.TreeColumnRenderer; //ComboBox cb = (ComboBox)sender; //switch (cb.SelectedIndex) //{ //case 0: //treeColumnRenderer.IsShowGlyphs = false; //break; //case 1: //treeColumnRenderer.IsShowGlyphs = true; //treeColumnRenderer.UseTriangles = false; //break; //case 2: //treeColumnRenderer.IsShowGlyphs = true; //treeColumnRenderer.UseTriangles = true; //break; //} //// Cause a redraw so that the changes to the renderer take effect //this.treeListView.Refresh(); //} private void WriteValue_Click(object sender, EventArgs e) { OPCTag tag = this.ListView.SelectedObject as OPCTag; if (tag != null) { tag.Value = this.WriteValueInput.Text; } else if (lastTag != null) { lastTag.Value = this.WriteValueInput.Text; } }
void OnTagChanged(object sender, TagEventArgs e) { //If we changed the tag then do not write the tag. if (sender != null) { if (sender.Equals(this)) { return; } } try { OPCTag tag = mTagsByName[e.Tag.Name]; AsyncWrite(tag); } catch (Exception ex) { //Error event } }
private void addNode(string name, string parentName = "") { // 应该先判断一下,这个 Key 在 map 中存在不存在。不存在,就添加 if (!keyTagMap.ContainsKey(name)) { OPCTag tag; if (parentName != "") { tag = new OPCTag(parentName, name); tag.id = seqId; if (keyTagMap.ContainsKey(parentName)) { OPCTag parent = keyTagMap[parentName]; tag.parent_id = parent.id; tag.root_id = parent.root_id; tag.isLeaf = true; if (allTagNames.Contains(name)) { tag.isRealTag = true; } parent.AddChild(tag); } } else { tag = new OPCTag(name); tag.parent_fullname = "root"; tag.id = seqId; tag.parent_id = 0; tag.root_id = tag.id; tag.isLeaf = false; tag.isRealTag = false; rootTagMap.Add(name, tag); } seqId++; tag.TagValueUpdate += new TagEventHandler(OnTagValueUpdate); keyTagMap.Add(name, tag); //Console.WriteLine("Value added for key = \"" + name + "\""); } }
void OnGroupAsyncWriteComplete(int TransactionID, int NumItems, ref Array ClientHandles, ref Array Errors) { try { for (int i = 1; i <= ClientHandles.Length; i++) { int handle = (int)ClientHandles.GetValue(i); OPCTag tag = null; if (mTagsByClientHandle.TryGetValue(handle, out tag)) { tag.Quality = ((int)Errors.GetValue(i) > 0) ? OPCQuality.OPCQualityBad : OPCQuality.OPCQualityGood; } mAcyncWriteTags.Remove(TransactionID); // 这里应该显示日志,或者其他的,可以展示错误的东西 } } catch (Exception ex) { } }
private void ShowTagProperties(OPCTag tag) { //OPCTag tag = listView.SelectedObject as OPCTag; //OPCTag focusedTag = listView.FocusedObject as OPCTag; if (this.TagValueBox.InvokeRequired) { //instansiate a delegate with the method ShowTagPropertiesDelegate myDelegate = new ShowTagPropertiesDelegate(ShowTagPropertiesWorker); //Invoke delegate this.TagValueBox.Invoke(myDelegate, tag); } else { if (tag != null && tag.isRealTag) { if (tag.Value == null) { this.TagValueBox.Text = "<null>"; } else { this.TagValueBox.Text = tag.Value.ToString(); } this.TagQualityBox.Text = tag.QualityText; this.TagTimestampBox.Text = tag.ItemTimeStampText; } else if (tag != null && !tag.isRealTag) { this.TagValueBox.Text = ""; this.TagQualityBox.Text = ""; this.TagTimestampBox.Text = ""; } this.WriteValueInput.Text = ""; } }
public void HandleSelectionChanged(ObjectListView listView) { // Most ListViews in the demo handle lists of people, so we try to cast SelectedObject and FocusedObject to be Persons. OPCTag p = listView.SelectedObject as OPCTag; string msg = p == null?listView.SelectedIndices.Count.ToString(CultureInfo.CurrentCulture) : String.Format("'{0}'", p.Name); OPCTag focused = listView.FocusedObject as OPCTag; string focusedMsg = focused == null ? "" : String.Format(". Focused on '{0}'", focused.Name); this.ToolStripStatus1 = String.IsNullOrEmpty(this.prefixForNextSelectionMessage) ? String.Format("Selected {0} of {1} items" + focusedMsg, msg, listView.GetItemCount()) : String.Format("{2}. Selected {0} of {1} items" + focusedMsg, msg, listView.GetItemCount(), this.prefixForNextSelectionMessage); //this.ToolStripStatus1 = String.Format("{2}. Selected {0} of {1} items" + focusedMsg, msg, listView.GetItemCount(), this.prefixForNextSelectionMessage); this.prefixForNextSelectionMessage = null; Console.WriteLine("this is in public void HandleSelectionChanged(ObjectListView listView)"); }
void OnGroupDataChange(int TransactionID, int NumItems, ref Array ClientHandles, ref Array ItemValues, ref Array Qualities, ref Array TimeStamps) { try { Console.WriteLine("in OPCClient, OnGroupDataChange, Thread id is: " + System.Threading.Thread.CurrentThread.ManagedThreadId); for (int i = 1; i <= NumItems; i++) { int handle = (int)ClientHandles.GetValue(i); if (mTagsByClientHandle.ContainsKey(handle)) { OPCTag tag = mTagsByClientHandle[handle]; tag.SetValue(this, ItemValues.GetValue(i)); tag.ItemTimeStamp = (DateTime)TimeStamps.GetValue(i); tag.Quality = (OPCQuality)Qualities.GetValue(i); tag.UpdateCount++; } } } catch (Exception ex) { } }
//public OPCTag() //{ //Children = new List<OPCTag>(); //} public void AddChild(OPCTag t) { t.Parent = this; Children.Add(t); }
public TagEventArgs(OPCTag tag) { Tag = tag; }
public bool AddTags(SortedDictionary <string, OPCTag> opcTags, string groupName = null, bool removeFormer = false) { Console.WriteLine("in OPCClient, AddTags 1"); Console.WriteLine("in OPCClient, AddTags, Thread id is: " + System.Threading.Thread.CurrentThread.ManagedThreadId); if (opcTags.Count == 0) { return(false); } if (removeFormer) { RemoveAllItems(); } if (groupName == null || groupName == "") { groupName = DefaultGroupName; } OPCGroup group = GetGroup(groupName); int[] ClientHandles = new int[opcTags.Count]; string[] tagNames = new string[opcTags.Count]; int handle = mTagsByName.Count + 1; int counter = 0; foreach (KeyValuePair <string, OPCTag> opcTag in opcTags) { if (mTagsByName.ContainsKey(opcTag.Value.Name)) { continue; } if ((opcTag.Value.Direction & TagDirection.Output) == TagDirection.Output) { opcTag.Value.TagChanged += new TagEventHandler(OnTagChanged); } ClientHandles[counter] = handle; tagNames[counter] = opcTag.Value.Name; handle++; counter++; } try { Array ar_itemNames = Array.CreateInstance(typeof(string), tagNames.Length + 1); ((Array)tagNames).CopyTo(ar_itemNames, 1); Array ar_itemClientHandles = Array.CreateInstance(typeof(int), tagNames.Length + 1); ((Array)ClientHandles).CopyTo(ar_itemClientHandles, 1); Array ar_Errors; group.OPCItems.AddItems(ar_itemClientHandles.Length - 1, ref ar_itemNames, ref ar_itemClientHandles, out itemServerHandles, out ar_Errors); foreach (object item in ItemServerHandles) { // 这里 如果 item 是 0 的话,会直接 crash。为什么 ItemServerHandles 会有大量的 0 呢? // 判断一下。或者用 nested try catch if (0 != (int)item) { OPCItem opcItem = group.OPCItems.GetOPCItem((int)item); if (opcItem != null) { //Save the opctag in a dictionary for quick lookup by name or by ClientHandle // 得到的 opcItem 的 ItemID 是什么?是传进去的Name吗? 是! OPCTag opcTag = opcTags[opcItem.ItemID]; opcTag.OPCItem = opcItem; opcTag.OPCGroup = group; mGroupTagsMap[group].Add(opcTag); mTagsByName.Add(opcTag.Name, opcTag); mTagsByClientHandle.Add(opcItem.ClientHandle, opcTag); } } } Console.WriteLine("in OPCClient, AddTags 2"); return(true); } catch (Exception err) { Console.WriteLine("in OPCClient, AddTags 3"); //没有任何权限的项,都是OPC服务器保留的系统项,此处可不做处理。 //MessageBox.Show("此项为系统保留项:"+err.Message,"提示信息"); // 这里应该写一个 错误处理 的方法,把每一个error code 对应的 错误信息,反馈给用户 } Console.WriteLine("in OPCClient, AddTags 4"); return(false); }
/// <summary> /// 【按钮】连接OPC服务器 /// </summary> private void btnConnLocalServer_Click(object sender, EventArgs e) { try { if (this.btnConnServer.Text == "连接") { if (String.IsNullOrEmpty(this.txtRemoteServerIP.Text)) { this.txtRemoteServerIP.Text = "127.0.0.1"; } opcClient.Initialize(cmbServerName.Text, this.txtRemoteServerIP.Text); bool result = opcClient.Connect(); if (!result) { // 在这里处理连接错误 MessageBox.Show("不能连接到OPC Server:" + cmbServerName.Text, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } this.btnConnServer.Enabled = false; // 启动Timer,去定时坚持是否连接正常 aTimer = new System.Timers.Timer(); aTimer.Interval = 1000; // Alternate method: create a Timer with an interval argument to the constructor. //aTimer = new System.Timers.Timer(2000); // Create a timer with a two second interval. //aTimer = new System.Timers.Timer(5000); // Hook up the Elapsed event for the timer. aTimer.Elapsed += OnTimedEvent; // Have the timer fire repeated events (true is the default) aTimer.AutoReset = false; // Start the timer aTimer.Enabled = true; TextOverlay textOverlay = this.treeListView.OverlayText as TextOverlay; textOverlay.Alignment = System.Drawing.ContentAlignment.MiddleCenter; textOverlay.TextColor = Color.Firebrick; textOverlay.BackColor = Color.AntiqueWhite; textOverlay.BorderColor = Color.DarkRed; textOverlay.BorderWidth = 4.0f; textOverlay.Font = new Font("宋体", 36); //textOverlay.Rotation = -5; textOverlay.Text = "正在加载Tag..."; this.treeListView.RefreshOverlays(); if (!treeInitialized) { InitializeTree(); } // 添加Tags,AddTags //opcClient.AddTags1(keyTagMap); AddTagsDelegate worker = AddTagsWorker; IAsyncResult asyncResult = worker.BeginInvoke(AddTagsCompleted, worker); //this.treeListView.BeginInvoke(new AddTagsDelegate(AddTagsWorker1)); this.btnConnServer.Text = "断开"; } else { aTimer.Enabled = false; aTimer = null; Thread.Sleep(1000); if (opcClient.Connected == true) { opcClient.Disconnect(); } // 这样行不行? // 显然不够,因为还得加 Column 类的 //this.treeListView = new BrightIdeasSoftware.TreeListView(); //this.treeListView.Clear(); this.treeListView.ClearObjects(); Thread.Sleep(1000); treeInitialized = false; keyTagMap.Clear(); rootTagMap.Clear(); allTagNames.Clear(); seqId = 1; lastTag = null; this.btnConnServer.Text = "连接"; this.ExpandAllNodes.Enabled = false; this.ExpandAllNodes.Text = "全部展开"; } } catch (Exception err) { MessageBox.Show("初始化出错:" + err.Message, "提示信息", MessageBoxButtons.OK, MessageBoxIcon.Warning); } }
/////////////////////////////////////////////////////////////////////////////////////////// /// <summary> /// Adds a tag to the opc server /// </summary> /// <param name="tag"></param> /////////////////////////////////////////////////////////////////////////////////////////// public bool AddTag(OPCTag opcTag, bool readProperty = true, string groupName = null) { //OPCTag opcTag = new OPCTag(tag); if (mTagsByName.ContainsKey(opcTag.Name)) { return(false); } // 这里要加 事件处理 ?? // 这里是处理 input 点、output点的。 // 如果设置成output点,当外部修改了这个点的value的时候,就通过事件处理,自动写到server端 // 先注掉吧。 // 这是是处理 往 server 端写数据的。如果把这个注掉,就没有主动写数据的地方了。 // 如果在其他地方,要写一个tag的值到server,只需要 tag.Value = xxxx,这样就可以了。 // 因为绑定了事件,最终会绕到这里这个OPCClient 的 OnTagChanged 方法 // 这个设计真绕 if ((opcTag.Direction & TagDirection.Output) == TagDirection.Output) { opcTag.TagChanged += new TagEventHandler(OnTagChanged); } //Add an OPC Group if the update time does not alread exist //OPCGroup group = GetGroup(opcTag.UpdateTime); // 这里用 Updatetime 来作为 group 的 Name,好,还是不好?好在:同一个 Updatetime 的在同一个group,更新的话,一起更新。 // 不好在:不够明确。 // 而且,这么写,添加 group 成了 添加item 驱动的了。 主动控制性不强 // 我希望的是,主动性更强一点。那设置一个 defaultGroupName if (groupName == null || groupName == "") { groupName = DefaultGroupName; } OPCGroup group = GetGroup(groupName); // 这里应该加一个 try catch,以防 这个Tag 在 server 端不存在 try { // 这里的AddItem 的第二个参数,应该是什么? // 一个数字?这个数字传到server,server数据有变化的时候再传回来,作为一个handle? OPCItem item = group.OPCItems.AddItem(opcTag.Name, mTagsByName.Count + 1); opcTag.OPCItem = item; opcTag.OPCGroup = group; if (item != null) { //Save the opctag in a dictionary for quick lookup by name or by ClientHandle mTagsByName.Add(opcTag.Name, opcTag); mTagsByClientHandle.Add(item.ClientHandle, opcTag); opcTag.ClientHandle = item.ClientHandle; opcTag.ServerHandle = item.ServerHandle; mGroupTagsMap[group].Add(opcTag); //ItemServerHandles.Add(opcTag.OPCItem.ServerHandle); //ItemServerHandles.SetValue //ItemServerHandles.SetValue(opcTag.OPCItem.ServerHandle, ItemServerHandles.Length); // 控制是不是添加Tag之后,就读一下Value呢 if (readProperty) { if (opcTag.isFirstUpdate) { ReadPropertyValues(ref opcTag); opcTag.isFirstUpdate = false; } } return(true); } else { return(false); } } catch (Exception err) { //没有任何权限的项,都是OPC服务器保留的系统项,此处可不做处理。 //MessageBox.Show("此项为系统保留项:"+err.Message,"提示信息"); return(false); // 这里应该写一个 错误处理 的方法,把每一个error code 对应的 错误信息,反馈给用户 } }