using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.IO;
using System.Xml.Serialization;
using System.Collections.ObjectModel;
using FObjBase;
using FLY.FeedbackRenZiJia.OBJ_INTERFACE;
using FLY.FeedbackRenZiJia.Common;
using FLY.FeedbackRenZiJia.IService;
using FLY.OBJComponents.Server;
using FLY.OBJComponents.Common;
using System.Net;
using FLY.FeedbackRenZiJia.Server.Model;
using PropertyChanged;
namespace FLY.FeedbackRenZiJia.Server
{
public class FeedbackHeat : IFeedbackHeat,Misc.ISaveToXml
{
#region markno
const int MARKNO_SAVE = 1;
const int MARKNO_LOAD = 2;
const int MARKNO_DELAY_ISCONNECTED = 3;
#endregion
#region IFeedbackHeat 成员
#region 参数
///
/// 作为客户端模式
///
public bool IsClient { get; set; }
public IPEndPoint PLCep { get; set; }
///
/// 自动控制使能
///
public bool IsAuto { get; set; }
///
/// 加热后起效延时(s)
///
public int Delay { get; set; } = 10;
///
/// 检测功能使能
///
public bool HasCheck { get; set; }
///
/// 手动加热步进
///
public int Step { get; set; } = 5;
#endregion
#region 动态数据
///
/// 通道数, 从测厚仪获取的!!!!
///
public int ChannelCnt { get; protected set; } = 44;
///
/// 分区数, 从测厚仪获取的!!!!
///
public int NBolts { get; protected set; } = 88;
///
/// 保存的加热策略名称
///
public string HeatsProductName { get; protected set; }="default";
/// 连接到PLC?
///
public bool IsConnectedWithPLC { get; set; }
///
/// 上一次加热修改时间
///
public DateTime LastChangedTime { get; set; } = DateTime.MinValue;
///
/// 当前
///
//public int[] Currs { get; set; }
#endregion
#region 异常检测
///
/// 烧了的加热棒
///
[DoNotCheckEquality]
public bool[] Bads { get; set; }
//{
// get { return mHeatCheck.Bads; }
//}
///
/// 当前风机启动中
///
public bool HasFan { get; set; }
///
/// 加热棒有电流
///
public bool HasElectricity { get; set; }
///
/// 线速度 大于 3m/min
///
public bool HasFilmVelocity { get; set; }
///
/// 检测线速度 使能
///
public bool HasCheckFilmVelocity { get; set; }
///
/// 当前正在检测的加热通道
///
public int CheckNo { get; set; } = -2;
///
/// 正在检测中
///
public bool CheckEnable { get; set; } = false;
#endregion
#endregion
private IPLCLink plc;
private FLY.Thick.Blowing.IService.IBlowing renzijia;
private FLY.Thick.Blowing.IService.IBlowingDetect mBDetect;
private UInt16 CurrsUpdate=0;
public HeatCell mHeatCell = new HeatCell();
HeatChanged mHeatChanged = new HeatChanged();
public HeatBuf mHeatBuf = new HeatBuf();
HeatCheck mHeatCheck = new HeatCheck();
public SnapShotBuf mSnapShotBuf = new SnapShotBuf();
HistoryDb mHistoryDb;
///
/// 报警系统
///
WarningSystem mWarning;
static FeedbackHeat()
{
Misc.SaveToXmlHepler.Regist(typeof(HeatCell));
Misc.SaveToXmlHepler.Regist(typeof(HeatBuf));
}
public FeedbackHeat()
{
PLCep = Misc.StringConverter.ToIPEndPoint("192.168.50.60:502");
Load();
if (IsClient)
plc = new PLCLink(PLCep);
else
plc = new HMI();
plc.PropertyChanged += new PropertyChangedEventHandler(hmi_PropertyChanged);
HasCheckFilmVelocity = plc.HasElectricity;
HasFan = plc.HasFan;
InitBuf();
//-------------------------------------------------------------------
PropertyChanged += new PropertyChangedEventHandler(FeedbackHeat_PropertyChanged);
//-------------------------------------------------------------------
//HeatBuf
//UpdateTotalDelay();
//-------------------------------------------------------------------
//HeatCell
mHeatCell.Init(mHeatBuf);
mHeatCell.PreHeatApplyEvent = (c) => {
//有开风机才能加热
if ((HasCheck) && (!HasFan))
return false;//返回false,不能加热
//检测时,也是使用 HeatApply 确定加热的,要把下面注解掉。所以只能寄望于客户不要按HeatApply
//检测中,不能改变加热
//if (mHeatCheck.Enable)
// return false;
return true;
};
mHeatCell.AfterHeatApplyEvent += (c) => {
//检测中,不保存加热
if (mHeatCheck.Enable)
return;
//保存最后一次加热
SaveHeatsLast();
//记录改变!!!!
mHeatChanged.Add(mHeatCell.Heats);
//复位undo模块
resetUndo();
//记录到数据库
if (lastLcThickHeat != null)
{
HeatChanged.ITEM heat = mHeatChanged.mItem.Last();
lastLcThickHeat.HTime = heat.Time;
lastLcThickHeat.Heats = heat.Heats;
setLcThickHeatIsStable(lastLcThickHeat);
mHistoryDb.AddThickHeat(lastLcThickHeat);
}
};
mHeatCell.AfterClearOffsetsEvent += (c) => {
//复位undo模块
resetUndo();
};
mHeatCell.PropertyChanged += new PropertyChangedEventHandler(mHeatCell_PropertyChanged);//当HeatCell.Heats 修改后,设置到HMI
Misc.BindingOperations.SetBinding(mHeatCell, "Kp", mHeatBuf, "Kp", Misc.BindingOperations.BindingMode.TwoWay);
if (!Directory.Exists("feedbackheats"))
Directory.CreateDirectory("feedbackheats");
//-------------------------------------------------------------------
//HeatChanged
Misc.BindingOperations.SetBinding(this.mHeatChanged, "Last", this, "LastChangedTime");
//-------------------------------------------------------------------
//HeatCheck
mHeatCheck.Init(mHeatCell);
mHeatCheck.PropertyChanged += new PropertyChangedEventHandler(mHeatCheck_PropertyChanged);
Misc.BindingOperations.SetBinding(this, "HasElectricity", mHeatCheck, "HasElectricity");
Misc.BindingOperations.SetBinding(this, "HasCheck", mHeatCheck, "Has");
Misc.BindingOperations.SetBinding(mHeatCheck, "Enable", this, "CheckEnable", Misc.BindingOperations.BindingMode.TwoWay);
Misc.BindingOperations.SetBinding(mHeatCheck, "CheckNo", this, "CheckNo");
Misc.BindingOperations.SetBinding(mHeatCheck, "Bads", this, "Bads");
//mHeatCheck.PropertyChanged += (s, e) =>
//{
// if (e.PropertyName == "Bads")
// {
// NotifyPropertyChanged("Bads");
// }
//};
if (plc is PLCLink)
{
((PLCLink)plc).Start();
}
}
void mHeatCheck_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Enable")
{
if (mHeatCheck.Enable)
{
if (!IsConnectedWithPLC)
{
//连接断开
mHeatCheck.Enable = false;
}
else if ((HasCheck) && (!HasFan))
{
//风机没启动,要关闭加热
mHeatCheck.Enable = false;
}
else
{
//需要关闭自控
IsAuto = false;
}
}
}
}
#region 异常
void InitError()
{
//--------------------------------------------------------------------------------
//连接断开事件
FObjBase.PollModule.Current.Poll_Config(PollModule.POLL_CONFIG.ADD,
() =>
{
Misc.BindingOperations.SetBinding(this, "IsConnectedWithPLC", () =>
{
bool b = !IsConnectedWithPLC;
ERR_STATE state = b ? ERR_STATE.ON : ERR_STATE.OFF;
ERRNO errno = ERRNOs.ERRNO_PLC_DISCONNECTED;
mWarning.Add(errno.Code, errno.Descrption, state);
});
}, TimeSpan.FromSeconds(3), true, false, this, MARKNO_DELAY_ISCONNECTED, true);
//------------------------------------------------------------------------
//检测功能的结果
this.PropertyChanged += (s, e) =>
{
if (e.PropertyName == "HasCheck")
{
if (!HasCheck)
{
ERRNO[] eRRNOs = new ERRNO[] {
ERRNOs.ERRNO_NO_FAN,
ERRNOs.ERRNO_OPEN_CIRCUIT,
ERRNOs.ERRNO_SHORT_CIRCUIT,
ERRNOs.ERRNO_POWER_OFF
};
foreach (ERRNO eRRNO in eRRNOs)
{
mWarning.Add(eRRNO.Code, eRRNO.Descrption, ERR_STATE.OFF);
}
}
return;
}
else if (e.PropertyName == "HasFan")
{
if (HasCheck)
{
ERR_STATE state = (!HasFan) ? ERR_STATE.ON : ERR_STATE.OFF;
ERRNO errno = ERRNOs.ERRNO_NO_FAN;
mWarning.Add(errno.Code, errno.Descrption, state);
}
}
};
//------------------------------------------------------------------------
//检测功能的结果
Dictionary error_property = new Dictionary();
error_property.Add("OpenCircuit", ERRNOs.ERRNO_OPEN_CIRCUIT);
error_property.Add("ShortCircuit", ERRNOs.ERRNO_SHORT_CIRCUIT);
error_property.Add("PowerOff", ERRNOs.ERRNO_POWER_OFF);
mHeatCheck.PropertyChanged += (s, e) =>
{
if (HasCheck)
{
if (error_property.ContainsKey(e.PropertyName))
{
bool b = (bool)Misc.PropertiesManager.GetValue(mHeatCheck, e.PropertyName);
ERR_STATE state = b ? ERR_STATE.ON : ERR_STATE.OFF;
ERRNO errno = error_property[e.PropertyName];
mWarning.Add(errno.Code, errno.Descrption, state);
}
}
};
//------------------------------------------------------------------------
//线速度异常
this.PropertyChanged += (s, e) =>
{
if (e.PropertyName == "HasCheckFilmVelocity")
{
if (!HasCheckFilmVelocity)
{
ERRNO eRRNO = ERRNOs.ERRNO_NO_VELOCITY;
mWarning.Add(eRRNO.Code, eRRNO.Descrption, ERR_STATE.OFF);
}
}
else if (e.PropertyName == "HasFilmVelocity")
{
if (HasCheckFilmVelocity)
{
ERR_STATE b = (!HasFilmVelocity) ? ERR_STATE.ON : ERR_STATE.OFF;
ERRNO eRRNO = ERRNOs.ERRNO_NO_VELOCITY;
mWarning.Add(eRRNO.Code, eRRNO.Descrption, b);
}
}
};
}
#endregion
void InitBuf()
{
plc.ChannelCnt = (UInt16)ChannelCnt;
//Currs = new int[ChannelCnt];
mHeatChanged.Init(ChannelCnt);
mHeatBuf.Init(NBolts, ChannelCnt);
mHeatCell.Init2(NBolts, ChannelCnt);
//复位undo模块
resetUndo();
mSnapShotBuf.Init(NBolts, ChannelCnt);
}
void hmi_PropertyChanged(object s, PropertyChangedEventArgs _e)
{
FObjBase.PollModule.Current.Dispatcher.Invoke(
new PropertyChangedEventHandler(
(sender, e)=> {
if (e.PropertyName == "Errno")
{
if (plc.Errno == -1)
{
IsConnectedWithPLC = false;
}
else
{
IsConnectedWithPLC = true;
//刚成功连接上
//重新复制数据到 PLC
RecoverPLC();
}
}
else if (e.PropertyName == "HasElectricity")
{
HasElectricity = plc.HasElectricity;
}
else if (e.PropertyName == "HasFan")
{
HasFan = plc.HasFan;
}
}), s, _e);
}
List test_data = new List();
public int TestIndex { get; set; } = 0;
bool TestMode = false;
///
/// 从历史数据加载,模拟整个过程
///
public void Test()
{
TestMode = true;
//if (TestIndex == 0)
//{
// StreamReader sr = new StreamReader("test.csv", Encoding.GetEncoding("GB2312"));
// string header = sr.ReadLine();
// while (!sr.EndOfStream)
// {
// string str = sr.ReadLine();
// FlyData_FeedbackHeat d = new FlyData_FeedbackHeat();
// d.TryParse(header, str);
// test_data.Add(d);
// }
// sr.Close();
// NBolts = test_data[0].Thicks.Count();
// ChannelCnt = test_data[0].Heats.Count();
// Add(
// test_data[0].Time,
// test_data[0].Direction,
// test_data[0].OrgBoltNo,
// test_data[0].RotatePeriod,
// test_data[0].Thicks);
//}
//if (TestIndex < test_data.Count())
//{
// int i = TestIndex;
// FlyData_FeedbackHeat d = test_data[i];
// mHeatChanged.Test_SetHeats(d.Heats, d.HTime);
// mHeatCell.ModifyPreHeats(d.Heats);
// mHeatCell.HeatApply();
// Add(i + 1, d.Time, d.Direction, d.OrgBoltNo, d.Thicks);
// TestIndex++;
//}
TestMode = false;
}
void mHeatCell_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Heats")
{
Output(mHeatCell.Heats.ToArray());
}
}
void FeedbackHeat_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (GetSavePropertyNames().Contains(e.PropertyName))
{
//PollModule.Current.Poll_JustOnce(new PollModule.PollHandler(delegate()
//{
// //Save();//数据滞后保存!!!!!
//}), this, MARKNO_SAVE);
}
if (e.PropertyName == "ChannelCnt")
{
//重新初始化!!!!
InitBuf();
//滞后触发
PollModule.Current.Poll_JustOnce(new PollModule.PollHandler(delegate ()
{
LoadHeatsLast();
}), this, MARKNO_LOAD);
}
else if (e.PropertyName == "NBolts")
{
//重新初始化!!!!
InitBuf();
}
else if (e.PropertyName == "Delay")
{
//重新计算总延时!!!!
UpdateTotalDelay();
}
else if (e.PropertyName == "HasFan")
{
if ((HasCheck) &&(!HasFan))
{
//风机没开,停止一切动作。
StopAnyHeating();
}
}
else if (e.PropertyName == "IsAuto")
{
if (IsAuto)
{
//启动了自控,应该关闭检测
mHeatCheck.Enable = false;
}
}
else if (e.PropertyName == "IsConnectedWithPLC")
{
if (!IsConnectedWithPLC)
{
mHeatCheck.Enable = false;
IsAuto = false;
}
}
}
public void Init(
FLY.Thick.Blowing.Client.BlowingServiceClient renzijia,
FLY.Thick.Blowing.IService.IBlowingDetect bDetect,
FLY.OBJComponents.Server.WarningSystem warning,
HistoryDb historyDb
)
{
this.renzijia = renzijia;
mBDetect = bDetect;
mWarning = warning;
mHistoryDb = historyDb;
//新数据,与参数被修改时,都会收到事件,应该区别开
renzijia.DataEvent += (s, e) =>
{
Add(
e.Time,
e.EndTime,
e.IsBackw,
e.RPeriod,
e.RCnt,
e.OrgBoltNo,
e.RAngle,
e.FilmLength,
e.FilmVelocity,
e.K,
e.Thicks,
e.Boltmap
);
};
Misc.BindingOperations.SetBinding(renzijia, "NBolts", this, "NBolts");
Misc.BindingOperations.SetBinding(renzijia, "ChannelCnt", this, "ChannelCnt");
mBDetect.PropertyChanged += MBDetect_PropertyChanged;
InitError();
}
private void MBDetect_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "FilmLength")
{
UpdateTotalDelay();
}
else if (e.PropertyName == "FilmVelocity")
{
UpdateTotalDelay();
HasFilmVelocity = (mBDetect.FilmVelocity > 3);//大于3m/min 正常生产
//当线速度 很小,肯定是没生产,停止加热,停止自控
if (HasCheckFilmVelocity && (!HasFilmVelocity))
{
StopAnyHeating();
//停止自控
IsAuto = false;
}
}
}
///
/// 停止任何加热行为
///
void StopAnyHeating()
{
//停止自控
IsAuto = false;
//备份 加热策略
int[] preheats = mHeatCell.PreHeats.ToArray();
bool needrestore = true;
//停止检测加热棒
if (mHeatCheck.Enable)
{
mHeatCheck.Enable = false;
needrestore = false;
}
//停止加热
mHeatCell.ClearPreHeats();
mHeatCell.HeatApply();
//恢复 加热策略
if(needrestore)
mHeatCell.ModifyPreHeats(preheats);
}
void UpdateTotalDelay()
{
if (mBDetect == null)
return;
if (mBDetect.FilmVelocity < 10)
return;
int totaldelay = (int)(Delay + mBDetect.FilmLength / mBDetect.FilmVelocity * 60);
int t = (int)(mHeatBuf.Delay.TotalSeconds);
if (Math.Abs(totaldelay - t) > 5)
{
mHeatBuf.Delay = TimeSpan.FromSeconds(totaldelay);
}
}
UInt16[] last_heat;
UInt16 last_heatupdate;
void Output(int[] heats)
{
List list = new List();
for (int i = 0; i < ChannelCnt; i++)
{
UInt16 heat = (UInt16)heats[i];
if (heat < 0)
heat = 0;
else if (heat > 100)
heat = 100;
list.Add(heat);
}
plc.SetHeat(list);
last_heat = list.ToArray();
UInt16 heatupdate = (UInt16)(plc.HeatUpdate_R + 1);
if (heatupdate >100)
heatupdate = 1;
plc.HeatUpdate = heatupdate;
last_heatupdate = heatupdate;
}
void RecoverPLC()
{
plc.ChannelCnt = (UInt16)ChannelCnt;
if (last_heat != null)
{
plc.SetHeat(last_heat);
plc.HeatUpdate = last_heatupdate;
}
else
{
//设置全部0进去
plc.SetHeat(new UInt16[ChannelCnt]);
plc.HeatUpdate = plc.HeatUpdate;
}
}
void setLcThickHeatIsStable(Lc_ThickHeat lcThickHeat)
{
DateTime time = lcThickHeat.Time;
DateTime htime = lcThickHeat.HTime;
double filmLength = lcThickHeat.FilmLength;
double filmVelocity = lcThickHeat.FilmVelocity;
lcThickHeat.IsStable = time > (htime + TimeSpan.FromSeconds(Delay) + TimeSpan.FromMinutes(filmLength / filmVelocity));
}
///
/// 最后一次保存的记录
///
Lc_ThickHeat lastLcThickHeat=null;
void Add(DateTime time, DateTime endtime, bool isBackw, TimeSpan period, int rotateCnt,
int orgboltno, double rAngle, double filmLength, double filmVelocity, double K,
double[] frame, List boltMaps)
{
//1.求平均值
//2.每个螺丝,加热量的增量 = (Thick - Avg) * Factor;
//3.求出输出量, 输出值 = 当前值 + 增量
if (frame.Count() != NBolts)
return;
//检测数据有效性
int invalid_cnt = frame.Count(
(_d) => {return double.IsNaN(_d);}
);
if (invalid_cnt > NBolts / 2)//有一半数据都是无效的
return;
HeatChanged.ITEM heat = mHeatChanged.mItem.Last();
var lcThickHeat = new Lc_ThickHeat()
{
Time = time,
EndTime = endtime,
IsBackw = isBackw,
RPeriod = period,
RCnt = rotateCnt,
OrgBoltNo = orgboltno,
RAngle = rAngle,
FilmLength = filmLength,
FilmVelocity = filmVelocity,
K = K,
Thicks = frame,
Boltmap = boltMaps,
HTime = heat.Time,
Heats = heat.Heats
};
setLcThickHeatIsStable(lcThickHeat);
mHistoryDb.AddThickHeat(lcThickHeat);
lastLcThickHeat = lcThickHeat;
mHeatBuf.IsIntoAutoONo = mHeatCell.IsInAutoONo;
//添加到缓冲区, 计算分区平移
if (!mHeatBuf.Add(
time, endtime, isBackw?Misc.DIRECTION.BACKWARD:Misc.DIRECTION.FORWARD, period, rotateCnt,
orgboltno, rAngle, filmLength,
RealThicksToFrames(frame), boltMaps,
heat.Time, heat.Heats))
{
//数据有问题,不需要在处理
return;
}
if (mHeatBuf.IsIntoAutoONo != mHeatCell.IsInAutoONo)//状态切换了, 只能是变为false
{
if (mHeatBuf.IsIntoAutoONo == false)
{
if (mHeatBuf.AutoONoResult == EAutoONoResult.OK)
{
if (renzijia.OrgBoltNo != mHeatBuf.BestOrgBoltNo)
{
renzijia.OrgBoltNo = mHeatBuf.BestOrgBoltNo;
renzijia.Apply();
}
}
//对位完成
mHeatCell.IsAutoONo = false;
}
}
FlyData_FeedbackHeat d = mHeatBuf.mData.Last();
mHeatCell.SetThickPercents(d.Thicks);
if (IsAuto && lcThickHeat.IsStable)//如果自控中!!!
{
mHeatCell.Auto();
}
}
int[] RealThicksToFrames(IEnumerable realthicks)
{
return realthicks.Select(t =>
{
if (double.IsNaN(t))
return Misc.MyBase.NULL_VALUE;
else
return (int)(t * 100);
}).ToArray();
}
bool Load()
{
return Misc.SaveToXmlHepler.Load("feedback.xml", this);
}
void Save()
{
Misc.SaveToXmlHepler.Save("feedback.xml", this);
}
#region 撤销
///
/// undo 的序号
///
public int UndoIdx { get; private set; }
///
/// 在撤销中
///
public bool IsInUndo { get; private set; }
///
/// 这次撤销动作的时间
///
public DateTime UndoTime { get; private set; }
//读取 UndoIdx 的 加热
public void Undo()
{
updateUodo(UndoIdx - 1);
}
public void Redo()
{
updateUodo(UndoIdx + 1);
}
void updateUodo(int idx)
{
if (idx < 0)
return;
else if (idx >= mHeatChanged.mItem.Count())
return;
mHeatCell.ModifyPreHeats(mHeatChanged.mItem[idx].Heats);
UndoTime = mHeatChanged.mItem[idx].Time;
IsInUndo = idx <= mHeatChanged.mItem.Count() - 1;
UndoIdx = idx;
}
void resetUndo()
{
UndoIdx = mHeatChanged.mItem.Count() - 1;
UndoTime = DateTime.MinValue;
IsInUndo = false;
}
#endregion
#region IFeedbackHeat 成员
public void Apply()
{
Save();
}
private void SaveHeatsLast()
{
string path = @"feedbackheats\最后记录.xml";
FeedbackHeatsMark mark = new FeedbackHeatsMark();
mark.heats = mHeatCell.Heats.ToArray();
mark.Save(path);
}
private void LoadHeatsLast()
{
string path = @"feedbackheats\最后记录.xml";
FeedbackHeatsMark mark = FeedbackHeatsMark.Load(path);
if ((mark != null) && (mark.heats != null))
{
mHeatCell.ModifyPreHeats(mark.heats);
}
}
#region 加热配置读写
public void SaveHeats(string productname)
{
string path = @"feedbackheats\" + productname + ".xml";
HeatsProductName = productname;
FeedbackHeatsMark mark = new FeedbackHeatsMark();
mark.heats = mHeatCell.Heats.ToArray();
mark.Save(path);
}
///
/// 获取保存的加热量文件列表 返回类型为 List<string>
///
///
///
public void GetHeatsFileList(AsyncCBHandler AsyncDelegate, object AsyncState)
{
DirectoryInfo dinfo = new DirectoryInfo(@"feedbackheats");
List filenames = new List();
if (dinfo.Exists)
{
foreach (FileInfo info in dinfo.GetFiles())
{
if (Path.GetExtension(info.Name) == ".xml")
{
filenames.Add(Path.GetFileNameWithoutExtension(info.Name));
}
}
}
AsyncDelegate(AsyncState, filenames);
}
///
/// 删除 加热量文件
///
///
public void DelHeatsFile(string productname)
{
string path = @"feedbackheats\" + productname + ".xml";
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
}
///
/// 加载 加热量文件
///
///
public void LoadHeatsFile(string productname)
{
string path = @"feedbackheats\" + productname + ".xml";
HeatsProductName = productname;
FeedbackHeatsMark mark = FeedbackHeatsMark.Load(path);
if ((mark != null) && (mark.heats != null))
{
mHeatCell.ModifyPreHeats(mark.heats);
}
}
#endregion
#endregion
#region INotifyPropertyChanged 成员
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyname)
{
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
#endregion
#region ISaveToXml 成员
public string[] GetSavePropertyNames()
{
return new string[]{
"Step",
"Delay",
"HasCheck",
"HeatsProductName",
"HasCheckFilmVelocity",
"IsClient",
"PLCep"
};
}
#endregion
}
}