在上文成功的建立和OPCServer的连接之后,就可以和Server进行互操作..
主要的操作有:读,写以及捕捉数据的变化..
捕捉数据的变化是被动操作..服务器会将变化的数据发送到客户端..客户端只需要在连接Server时候,生成的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[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[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#客户端的通讯已经介绍完毕,基本满足简单应用,更深层的需要可能还需要继续努力..
奉献上完整代码:
![]()
//服务器返回项
{
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的浏览等..以后,如果用到这方面的东西,再继续补充...