在上文成功的建立和OPCServer的连接之后,就可以和Server进行互操作..
主要的操作有:读,写以及捕捉数据的变化..
捕捉数据的变化是被动操作..服务器会将变化的数据发送到客户端..客户端只需要在连接Server时候,生成的theGrp_DataChanged事件中,写代码就可以..

捕捉数据变化 void theGrp_DataChanged(object sender, DataChangeEventArgs e)
{
lock (_dtPoint)
{
foreach (OPCItemState s in e.sts)
{
if (HRESULTS.Succeeded(s.Error))
{
int handClent = s.HandleClient;
for (int i = 0; i < Count; i++)
{
if (Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]) == handClent)
{
_dtPoint.Rows[i]["PV"] = s.DataValue;
break;
}
}
}
}
}
}
根据HandleClient来判断是哪一个数据项发生变化..降变化的数据保存下来,供系统调用..
数据的读写操作....
theGrp_ReadCompleted和theGrp_WriteCompleted 这个两个方法,是获取操作结果的方法..
在theGrp_ReadCompleted中可以,获取到最近一次读取的数据项的值..
代码如下:

获取读取数据结果lock (_dtPoint)
{
foreach (OPCItemState s in e.sts)
{
if (HRESULTS.Succeeded(s.Error))
{
int handClent = s.HandleClient;
for (int i = 0; i < Count; i++)
{
if (Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]) == handClent)
{
_dtPoint.Rows[i]["PV"] = s.DataValue;
break;
}
}
}
}
}
将读取到的数据更新到数据表中..
读取数据代码:

读取最新数据int[] readSer = new int[dtPoint.Rows.Count];
for (int i = 0; i < dtPoint.Rows.Count; i++)
{
readSer[i] = Convert.ToInt32(dtPoint.Rows[i]["ServerHandel"]);
}
int cancelID;
int[] arrErr;
int transactionID = Convert.ToInt32(DateTime.Now.ToString("yyMMddHHmm"));
theGrp.Read(readSer, transactionID, out cancelID, out arrErr);
其中,readSer数组保存的是服务器端句柄..transactionID 是一个标致,在返回读取结果的时候,会用到,可以判断是不是上次读取的结果..
写入数据的代码如下:

写入数据int[] handle = new int[1];
for (int i = 0; i < this.Count; i++)
{
if (this.dtPoint.Rows[i]["PointName"].ToString() == pointName)
{
handle[0] = Convert.ToInt32(this.dtPoint.Rows[i]["ServerHandel"]);
break;
}
}
object[] itemValues = new object[1];
itemValues[0] = (object)value;
int[] ax;
bool re = this.theGrp.Write(handle, itemValues, out ax);
最后,因为项目的需要,自己写了两个写入的方法..1个单值写入,1个一次多值写入..写出来,只是为了方便大家的使用,代码并没有什么含金量,如下:

写入数据(自定义方法)/// <summary>
/// 写入数值(一次写入多个)
/// </summary>
/// <param name="pointName"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool pvWrite(string[] pointName, string[] value)
{
int[] handle = new int[pointName.Length];
for (int i = 0; i < handle.Length; i++)
{
for (int j = 0; j < Count; j++)
{
if (dtPoint.Rows[j]["PointName"].ToString() == pointName[i])
{
handle[i] = Convert.ToInt32(dtPoint.Rows[j]["ServerHandel"]);
break;
}
}
}
int[] ax;
bool re = this.theGrp.Write(handle, (object[])value, out ax);
return re;
}
/// <summary>
/// 写入数值(单值写入)
/// </summary>
/// <param name="pointName"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool pvWrite(string pointName, string value)
{
int[] handle = new int[1];
for (int i = 0; i < this.Count; i++)
{
if (this.dtPoint.Rows[i]["PointName"].ToString() == pointName)
{
handle[0] = Convert.ToInt32(this.dtPoint.Rows[i]["ServerHandel"]);
break;
}
}
object[] itemValues = new object[1];
itemValues[0] = (object)value;
int[] ax;
bool re = this.theGrp.Write(handle, itemValues, out ax);
return re;
}
因为theGrp_WriteCompleted 方法,项目中没有使用到..所以,就没有添加代码,只是留了个空方法..
至此,OPCServer和c#客户端的通讯已经介绍完毕,基本满足简单应用,更深层的需要可能还需要继续努力..
奉献上完整代码:

写入数据(自定义方法)public OPCItemResult[] rItem//服务器返回项
{
get { return _rItem; }
set { _rItem = value; }
}
public OPCItemDef[] itemDefs//客户端项属性
{
set { _itemDefs = value; }
get { return _itemDefs; }
}
public int[] handlesSrv
{
get { return _handlesSrv; }
set { _handlesSrv = value; }
}
private static int[] _handlesSrv;//服务器端句柄
private static bool isConnect = false;
private static OPCItemResult[] _rItem = null;
private static OPCItemDef[] _itemDefs = null;
public bool IsConnect
{
get { return isConnect; }
set { isConnect = value; }
}
public int Count
{
set { _Count = value; }
get { return _Count; }
}
private static DataTable _dtPoint = null;
public DataTable dtPoint
{
get
{
return _dtPoint;
}
set
{
_dtPoint = value;
}
}
private static OpcServer _theSrv = null;
public OpcServer theSrv
{
set { _theSrv = value; }
get { return _theSrv; }
}
private static OpcGroup _theGrp = null;
public OpcGroup theGrp
{
set { _theGrp = value; }
get { return _theGrp; }
}
void theGrp_DataChanged(object sender, DataChangeEventArgs e)
{
lock (_dtPoint)
{
foreach (OPCItemState s in e.sts)
{
if (HRESULTS.Succeeded(s.Error))
{
int handClent = s.HandleClient;
for (int i = 0; i < Count; i++)
{
if (Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]) == handClent)
{
_dtPoint.Rows[i]["PV"] = s.DataValue;
break;
}
}
}
}
}
}
void theGrp_ReadCompleted(object sender, ReadCompleteEventArgs e)
{
lock (_dtPoint)
{
foreach (OPCItemState s in e.sts)
{
if (HRESULTS.Succeeded(s.Error))
{
int handClent = s.HandleClient;
for (int i = 0; i < Count; i++)
{
if (Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]) == handClent)
{
_dtPoint.Rows[i]["PV"] = s.DataValue;
break;
}
}
}
}
}
}
public bool Connect(string serverName, string serverAdress)
{
theSrv = new OpcServer();
theSrv.Connect(serverName, serverAdress);
Thread.Sleep(500);
_dtPoint = dal.SelPoint();
Count = _dtPoint.Rows.Count;
theGrp = theSrv.AddGroup("OPCGroup", false, 900);
itemDefs = new OPCItemDef[Count];
for (int i = 0; i < Count; i++)
{
itemDefs[i] = new OPCItemDef(_dtPoint.Rows[i]["PointName"].ToString() + ".PV", true, Convert.ToInt32(_dtPoint.Rows[i]["ClientHandel"]), VarEnum.VT_EMPTY);
}
theGrp.AddItems(itemDefs, out _rItem);
if (rItem == null) return false;
bool res = true;
for (int i = 0; i < Count; i++)
{
if (HRESULTS.Failed(rItem[i].Error))
{
res = false; //如果符合,则修改
break;
}
}
if (!res)
{
//this.lblErr.Text = "OPC服务器:添加组错误!";
theGrp.Remove(true);
theSrv.Disconnect();
return false;
}
handlesSrv = new int[Count];
for (int i = 0; i < Count; i++)
{
handlesSrv[i] = rItem[i].HandleServer;
_dtPoint.Rows[i]["ServerHandel"] = (object)handlesSrv[i];
}
theGrp.SetEnable(true);
theGrp.Active = true;
theGrp.DataChanged += new DataChangeEventHandler(theGrp_DataChanged);
return true;
}
/// <summary>
/// 写入数值(一次写入多个)
/// </summary>
/// <param name="pointName"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool pvWrite(string[] pointName, string[] value)
{
int[] handle = new int[pointName.Length];
for (int i = 0; i < handle.Length; i++)
{
for (int j = 0; j < Count; j++)
{
if (dtPoint.Rows[j]["PointName"].ToString() == pointName[i])
{
handle[i] = Convert.ToInt32(dtPoint.Rows[j]["ServerHandel"]);
break;
}
}
}
int[] ax;
bool re = this.theGrp.Write(handle, (object[])value, out ax);
return re;
}
/// <summary>
/// 写入数值(单值写入)
/// </summary>
/// <param name="pointName"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool pvWrite(string pointName, string value)
{
int[] handle = new int[1];
for (int i = 0; i < this.Count; i++)
{
if (this.dtPoint.Rows[i]["PointName"].ToString() == pointName)
{
handle[0] = Convert.ToInt32(this.dtPoint.Rows[i]["ServerHandel"]);
break;
}
}
object[] itemValues = new object[1];
itemValues[0] = (object)value;
int[] ax;
bool re = this.theGrp.Write(handle, itemValues, out ax);
return re;
}
数据库中Point创建的SQL语句
if exists (select * from dbo.sysobjects where id = object_id(N'[dbo].[Point]') and OBJECTPROPERTY(id, N'IsUserTable') = 1)
drop table [dbo].[Point]
GO
CREATE TABLE [dbo].[Point] (
[PointId] [int] NOT NULL ,
[PointName] [varchar] (20) COLLATE Chinese_PRC_CI_AS NULL ,
[PointDesc] [varchar] (50) COLLATE Chinese_PRC_CI_AS NULL ,
[ClientHandel] [int] NULL ,
[ServerHandel] [int] NULL ,
[PV] [char] (10) COLLATE Chinese_PRC_CI_AS NULL ,
[isUse] [int] NULL
) ON [PRIMARY]
GO
到此,该系列结束..还包括很多应用没有提到,包括OPCServer的浏览等..以后,如果用到这方面的东西,再继续补充...
posted @ 2010-05-21 17:49 rockey 阅读(643) 评论(3)
编辑