Commit d6b402b3 authored by 潘栩锋's avatar 潘栩锋 🚴

还在构思中

parent 738777ce
using FLY.OBJComponents.Common;
using FLY.OBJComponents.IService;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace FLY.OBJComponents.Client
{
/// <summary>
/// IBuffer<T>的分页观察
///
/// </summary>
public class BufferPage<T> : INotifyPropertyChanged, IDisposable
{
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// IBuffer<T>
/// </summary>
public IBuffer<T> Buffer;
#region property
/// <summary>
/// 窗口中的数据
/// </summary>
public ObservableCollection<T> Record { get; } = new ObservableCollection<T>();
/// <summary>
/// 最新数据的ID,就是 Buffer.NewestID,
/// 但不直接使用Buffer.NewestID,因为 Buffer.NewestID可能与接收的数据滞后,或超前
/// </summary>
public int RecordLastID { get; private set; } = -1;
/// <summary>
/// 保持最新,改变WindowID 无效,它是输入
/// </summary>
public bool IsKeepNewest { get; private set; }
/// <summary>
/// 窗口最后一行的目标ID,它是输入
/// </summary>
public int WindowID { get; private set; }
private int size = 30;
/// <summary>
/// 窗口大小
/// </summary>
public int Size
{
get { return size; }
set
{
if (value < 10)
value = 10;
if (size != value)
{
size = value;
}
}
}
/// <summary>
/// buffer 的总页数
/// </summary>
public int TotalPages { get; private set; }
/// <summary>
/// 当前页码, 页码从1-TotalPages
/// </summary>
public int CurrentPage { get; private set; }
/// <summary>
/// 最后一页
/// </summary>
public bool IsLastPage => (CurrentPage >= TotalPages);
/// <summary>
/// 最前一页
/// </summary>
public bool IsFirstPage => (CurrentPage <= 1);
#endregion
public BufferPage(IBuffer<T> buffer, int size = 30)
{
Size = size;
Buffer = buffer;
IsKeepNewest = true;
WindowID = Buffer.NewestID;//显示最新数据!!!
updatePageInfo();
GetWindow();
Buffer.BufferChanged += Buffer_BufferChanged;
Buffer.PropertyChanged += Buffer_PropertyChanged;
this.PropertyChanged += BufferWindow_PropertyChanged;
}
private void BufferWindow_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Size")
{
updatePageInfo();
GetWindow();
}
else if (e.PropertyName == "WindowID")
{
updatePageInfo();
}
else if (e.PropertyName == "IsKeepNewest")
{
}
}
void GetWindow()
{
if (IsKeepNewest)
{
Buffer.GetRecord(Size, (asyncContext, retData) =>
{
GetRecordReponse<T> getRecordReponse = retData as GetRecordReponse<T>;
if (getRecordReponse.Items != null)
{
WindowID = getRecordReponse.LastID;
push(getRecordReponse.LastID, getRecordReponse.Items);
}
}, null);
}
else
{
int firstId = (CurrentPage - 1) * Size;
int lastId = firstId + Size - 1;
if (lastId > Buffer.NewestID)
lastId = Buffer.NewestID;
if (lastId >= firstId)
{
int size = lastId - firstId + 1;
Buffer.GetRecord(lastId, size, (asyncContext, retData) =>
{
GetRecordReponse<T> getRecordReponse = retData as GetRecordReponse<T>;
if (getRecordReponse.Items != null)
push(getRecordReponse.LastID, getRecordReponse.Items);
}, null);
}
}
}
private void Buffer_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if ((e.PropertyName == "Count") ||
(e.PropertyName == "NewestID"))
{
updatePageInfo();
}
}
private void Buffer_BufferChanged(object sender, NotifyBufferChangedEventArgs<T> e)
{
switch (e.Action)
{
case NotifyBufferChangedAction.Add:
{
int newEndingID = e.EndingID;
int nFirstID = e.EndingID;
int nLastID = newEndingID;
if (IsKeepNewest)//保持数据最新
{
WindowID = newEndingID;
}
int wLastID = WindowID;
//以 nFirstID 为0 偏移
int offset = -nFirstID;
wLastID += offset;
nLastID += offset;
if (wLastID < -1)
{
//新数据不用添加到Record
}
else
{
push(newEndingID, (IList<T>)e.Items);
}
}
break;
case NotifyBufferChangedAction.Replace:
{
push(e.EndingID, (IList<T>)e.Items);
}
break;
case NotifyBufferChangedAction.Remove:
{
remove(e.EndingID, 1);
}
break;
case NotifyBufferChangedAction.Reset:
{
//数据清空
Record.Clear();
RecordLastID = 0;
WindowID = 0;
}
break;
case NotifyBufferChangedAction.IsConnected:
{
//重新连接上服务器,获取全部数据
GetWindow();
}
break;
}
}
void push(int items_lastID, IList<T> items)
{
if (Record.Count() == 0)
{
foreach (T item in items)
{
Record.Add(item);
}
RecordLastID = items_lastID;
}
else
{
//找Record 中的数据,是否与新推送过来的数据有交集
int firstID = items_lastID - items.Count + 1;
int lastID = items_lastID;
int rFirstID = RecordLastID - Record.Count() + 1;
int rLastID = RecordLastID;
//转换坐标,以rFirstID=0,全部平移
int offset = -rFirstID;
firstID += offset;
lastID += offset;
rLastID += offset;// = Record.Count()-1
rFirstID = 0;// = 0
if (lastID < -1)//新数据在旧数据前面,不能合并
{
Record.Clear();
foreach (T item in items)
{
Record.Add(item);
}
RecordLastID = items_lastID;
}
else if (firstID > Record.Count())//新数据在旧数据后面,不能合并
{
Record.Clear();
foreach (T item in items)
{
Record.Add(item);
}
RecordLastID = items_lastID;
}
else//可以拼接
{
for (int i = lastID; i >= firstID; i--)
{
int items_idx = i - firstID;
T item = items[items_idx];
if (i > rLastID)
{
if (Record.Count > (rLastID + 1))
Record.Insert(rLastID + 1, item);
else
Record.Add(item);
}
else if (i >= 0)
{
Record[i] = item;
}
else
{
Record.Insert(0, item);
}
}
if (lastID > rLastID)
RecordLastID = items_lastID;
}
}
FitWindow();
}
void remove(int items_lastID, int cnt)
{
if (Record.Count() == 0)
{
return;
}
else
{
//找Record 中的数据,是否与新推送过来的数据有交集
int firstID = items_lastID - cnt + 1;
int lastID = items_lastID;
int rFirstID = RecordLastID - Record.Count() + 1;
int rLastID = RecordLastID;
//转换坐标,以rFirstID=0,全部平移
int offset = -rFirstID;
firstID += offset;
lastID += offset;
rLastID += offset;// = Record.Count() - 1;
rFirstID = 0;
if (lastID <= -1)//被删除数据在当前数据前面,什么都不用做
{
return;
}
else //被删除数据与当前数据有交集
{
//重新问buffer获取当前数据块
Record.Clear();
RecordLastID = -1;
GetWindow();
}
}
}
/// <summary>
/// 把多出window范围的数据删除
/// </summary>
void FitWindow()
{
//找Record 中的数据,是否与新推送过来的数据有交集
int wFirstID = WindowID - Size + 1;
int wLastID = WindowID;
int rFirstID = RecordLastID - Record.Count() + 1;
int rLastID = RecordLastID;
//转换坐标,以rFirstID=0,全部平移
int offset = -rFirstID;
wFirstID += offset;
wLastID += offset;
rLastID += offset;
rFirstID += offset;
if (wLastID < 0)//WINDOW在旧数据前面,不能合并
{
Record.Clear();
RecordLastID = 0;
}
else if (wFirstID > Record.Count() - 1)//WINDOW在旧数据后面,不能合并
{
Record.Clear();
RecordLastID = 0;
}
else//有数据剩下
{
if ((wLastID >= rLastID) && (wFirstID <= rFirstID))//在显示范围内,不用删除
{
return;
}
else
{
//删除后面
int cnt = rLastID - wLastID;
for (int i = 0; i < cnt; i++)
{
Record.RemoveAt(Record.Count() - 1);
}
if (cnt >= 0)
{
RecordLastID -= cnt;
}
cnt = wFirstID - rFirstID;
//删除前面
for (int i = 0; i < cnt; i++)
{
Record.RemoveAt(0);
}
}
}
}
void updatePageInfo()
{
if (Buffer.Count == 0)
{
//没有数据
CurrentPage = 0;
TotalPages = 0;
return;
}
//buffer 第1个数据ID
int firstID = Buffer.NewestID - (Buffer.Count - 1);
//buffer 最后一个数据ID
int lastID = Buffer.NewestID;
//当前页面最后一个数据ID
int wLastID = WindowID;
//buffer 第1个数据所在的全局页码
int gFirstPage = firstID / Size;
//buffer 最后一个数据所在的全局页码
int gLastPage = lastID / Size;
//当前全局页码
int gWdPage = wLastID / Size;
//总页数
int totalpages = gLastPage - gFirstPage + 1;
//当前页码
int page = gWdPage - gFirstPage + 1;
//限制当前页码
if (page < 1)
page = 1;
else if (page > totalpages)
page = totalpages;
CurrentPage = page;
TotalPages = totalpages;
}
#region 窗口移动
/// <summary>
/// 下一页, 让窗口向后移,TailerID+=Capacity
/// </summary>
public void MoveNextPage()
{
IsKeepNewest = false;
MovePage(CurrentPage + 1);
}
/// <summary>
/// 上一页,让窗口向前移,TailerID-=Capacity
/// </summary>
public void MovePrePage()
{
IsKeepNewest = false;
MovePage(CurrentPage - 1);
}
/// <summary>
/// 移动到最新数据
/// </summary>
public void MoveNewest()
{
IsKeepNewest = true;
GetWindow();
}
/// <summary>
/// 移动到某页
/// </summary>
/// <param name="page"></param>
public void MovePage(int page)
{
if (CurrentPage != page)
{
if ((page <= TotalPages) && (page > 0))
{
WindowID += Size * (page - CurrentPage);
GetWindow();
}
}
}
/// <summary>
/// 通过 最后数据的ID,移动
/// </summary>
/// <param name="lastID"></param>
public void Move(int lastID)
{
IsKeepNewest = false;
WindowID = lastID;
GetWindow();
}
#endregion
/// <summary>
/// 释放窗口,数据不再更新
/// </summary>
public void Dispose()
{
}
}
}
......@@ -30,29 +30,10 @@ namespace FLY.OBJComponents.Client
IFConn mConn;
UInt32 mServerID;
/// <summary>
/// 数据是从服务器推送过来的,忽略属性变化事件
/// </summary>
bool isIgnore = false;
public BufferServiceClient(UInt32 serverid)
{
mServerID = serverid;
this.PropertyChanged += BufferServiceClient_PropertyChanged;
}
private void BufferServiceClient_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (isIgnore)
return;
Dictionary<string, object> datas = new Dictionary<string, object>
{
{ e.PropertyName, Misc.PropertiesManager.GetValue(sender, e.PropertyName) }
};
string json = JsonConvert.SerializeObject(datas);
CurrObjSys.SetValueEx(mConn, mServerID, ID, BUFFER_OBJ_INTERFACE.SET_PARAMS,
Misc.Converter.StringToBytes(json));
}
public override void Dispose()
......@@ -69,6 +50,9 @@ namespace FLY.OBJComponents.Client
CurrObjSys.GetValueEx(
mConn, mServerID, ID,
BUFFER_OBJ_INTERFACE.GET_PARAMS);
CurrObjSys.GetValueEx(
mConn, mServerID, ID,
BUFFER_OBJ_INTERFACE.GET_STATUS);
CurrObjSys.SenseConfigEx(
mConn, mServerID, ID,
......@@ -90,19 +74,16 @@ namespace FLY.OBJComponents.Client
case BUFFER_OBJ_INTERFACE.GET_PARAMS:
{
string json = Misc.Converter.BytesToString(infodata);
Dictionary<string, object> datas = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
//设置属性
//屏蔽属性改变后,设置到服务器
isIgnore = true;
foreach (KeyValuePair<string, object> kv in datas)
{
PropertiesManager_JSON.SetValue(this, kv.Key, kv.Value);
}
isIgnore = false;
var p = Newtonsoft.Json.JsonConvert.DeserializeObject<BUFFER_OBJ_INTERFACE.Pack_Params>(json);
Capacity = p.capcity;
}
break;
case BUFFER_OBJ_INTERFACE.GET_STATUS:
{
string json = Misc.Converter.BytesToString(infodata);
var p = Newtonsoft.Json.JsonConvert.DeserializeObject<BUFFER_OBJ_INTERFACE.Pack_Status>(json);
Count = p.count;
NewestID = p.newestId;
}
break;
......@@ -112,6 +93,7 @@ namespace FLY.OBJComponents.Client
{
switch (infoid)
{
case BUFFER_OBJ_INTERFACE.PUSH_STATUS:
case BUFFER_OBJ_INTERFACE.PUSH_PARAMS:
{
PushGetValue(from, srcid, infoid, infodata);
......@@ -175,5 +157,16 @@ namespace FLY.OBJComponents.Client
asyncCB, asyncContext
);
}
public void Apply()
{
var p = new BUFFER_OBJ_INTERFACE.Pack_Params()
{
capcity = Capacity
};
string json = Newtonsoft.Json.JsonConvert.SerializeObject(p);
CurrObjSys.SetValueEx(mConn, mServerID, ID, BUFFER_OBJ_INTERFACE.SET_PARAMS,
Misc.Converter.StringToBytes(json));
}
}
}
......@@ -18,9 +18,30 @@ namespace FLY.OBJComponents.Common
public class NotifyBufferChangedEventArgs<T> : EventArgs
{
/// <summary>
/// 动作
/// </summary>
public NotifyBufferChangedAction Action { get; set; }
/// <summary>
/// 被修改的数据,可能为空,需要再向Buffer 获取
/// </summary>
public IEnumerable<T> Items { get; set; }
/// <summary>
/// 最后一条记录ID
/// </summary>
public int EndingID { get; set; }
/// <summary>
/// 当前修改数据量
/// </summary>
public int Count { get; set; }
/// <summary>
/// 列表最后一条记录
/// </summary>
public int BufferNewestID { get; set; }
/// <summary>
/// 列表总数据量
/// </summary>
public int BufferCount { get; set; }
}
public enum NotifyBufferChangedAction
......
......@@ -47,6 +47,7 @@
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="Client\BufferPage.cs" />
<Compile Include="Client\BufferWindow.cs" />
<Compile Include="Client\BufferServiceClient.cs" />
<Compile Include="Client\PLCProxySystemServiceClient.cs" />
......
......@@ -19,6 +19,15 @@ namespace FLY.OBJComponents.OBJ_INTERFACE
{
public int count;
}
public class Pack_Status
{
public int newestId;
public int count;
}
public class Pack_Params
{
public int capcity;
}
#endregion
#region SetValue
......@@ -33,6 +42,10 @@ namespace FLY.OBJComponents.OBJ_INTERFACE
/// Dictionary<string, object>
/// </summary>
public const UInt16 GET_PARAMS = 0;
/// <summary>
/// Pack_Status
/// </summary>
public const UInt16 GET_STATUS = 1;
#endregion
#region PushMsg
......@@ -41,9 +54,13 @@ namespace FLY.OBJComponents.OBJ_INTERFACE
/// </summary>
public const UInt16 PUSH_PARAMS = 0;
/// <summary>
/// Pack_Status
/// </summary>
public const UInt16 PUSH_STATUS = 1;
/// <summary>
/// NotifyBufferChangedEventArgs
/// </summary>
public const UInt16 PUSH_BUFFERCHANGED = 1;
public const UInt16 PUSH_BUFFERCHANGED = 10;
#endregion
#region Call
/// <summary>
......
......@@ -14,6 +14,8 @@ namespace FLY.OBJComponents.Server.OBJProxy
{
public class Buffer_OBJProxy<T> : FObj
{
const int MARKNO_PUSH_STATUS = 1;
const int MARKNO_PUSH_PARAMS = 2;
IBuffer<T> buffer;
public Buffer_OBJProxy(int objsys_idx, UInt32 id, IBuffer<T> buffer)
......@@ -36,16 +38,29 @@ namespace FLY.OBJComponents.Server.OBJProxy
private void Buffer_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
Dictionary<string, object> p = new Dictionary<string, object>
if ((e.PropertyName == "NewestID") ||
(e.PropertyName == "Count"))
{
{ e.PropertyName, Misc.PropertiesManager.GetValue(sender, e.PropertyName) }
};
string json = JsonConvert.SerializeObject(p);
CurrObjSys.PushObjInfoEx(
this, BUFFER_OBJ_INTERFACE.PUSH_PARAMS,
Misc.Converter.StringToBytes(json)
);
FObjBase.PollModule.Current.Poll_JustOnce(() =>
{
byte[] buf;
GetValue(null, 0, BUFFER_OBJ_INTERFACE.GET_STATUS, out buf);
CurrObjSys.PushObjInfoEx(
this, BUFFER_OBJ_INTERFACE.GET_STATUS,
buf);
}, this, MARKNO_PUSH_STATUS);
}
if (e.PropertyName == "Capacity")
{
FObjBase.PollModule.Current.Poll_JustOnce(() =>
{
byte[] buf;
GetValue(null, 0, BUFFER_OBJ_INTERFACE.GET_PARAMS, out buf);
CurrObjSys.PushObjInfoEx(
this, BUFFER_OBJ_INTERFACE.GET_PARAMS,
buf);
}, this, MARKNO_PUSH_PARAMS);
}
}
public override void SetValue(IFConn from, uint srcid, ushort memid, byte[] infodata)
......@@ -55,13 +70,8 @@ namespace FLY.OBJComponents.Server.OBJProxy
case BUFFER_OBJ_INTERFACE.SET_PARAMS:
{
string json = Misc.Converter.BytesToString(infodata);
Dictionary<string, object> p = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
foreach (var kv in p)
{
PropertiesManager_JSON.SetValue(buffer, kv.Key, kv.Value);
}
var p = Newtonsoft.Json.JsonConvert.DeserializeObject<BUFFER_OBJ_INTERFACE.Pack_Params>(json);
buffer.Capacity = p.capcity;
}
break;
}
......@@ -73,12 +83,21 @@ namespace FLY.OBJComponents.Server.OBJProxy
{
case BUFFER_OBJ_INTERFACE.GET_PARAMS:
{
Dictionary<string, object> p = new Dictionary<string, object>();
IEnumerable<string> propertynames = Misc.PropertiesManager.GetAllPropertyNames(buffer);
foreach (string pn in propertynames)
var p = new BUFFER_OBJ_INTERFACE.Pack_Params()
{
capcity = buffer.Capacity
};
string json = JsonConvert.SerializeObject(p);
infodata = Misc.Converter.StringToBytes(json);
}
break;
case BUFFER_OBJ_INTERFACE.GET_STATUS:
{
var p = new BUFFER_OBJ_INTERFACE.Pack_Status()
{
p.Add(pn, Misc.PropertiesManager.GetValue(buffer, pn));
}
newestId = buffer.NewestID,
count = buffer.Count
};
string json = JsonConvert.SerializeObject(p);
infodata = Misc.Converter.StringToBytes(json);
}
......
......@@ -66,9 +66,20 @@ namespace FLY.OBJComponents.Server
sqliteHelper.QueryTranAsync(sqls);
Count++;
BufferChanged?.Invoke(this, new NotifyBufferChangedEventArgs<TLc>()
{
Action = NotifyBufferChangedAction.Add,
EndingID = NewestID,
Count = 1,
Items = new TLc[] { lc },
BufferCount = Count,
BufferNewestID = NewestID
});
}
public void AddRange(IEnumerable<TLc> lcs)
{
{
if (lcs.Count() == 0)
return;
List<string> sqls = new List<string>();
foreach (var lc in lcs)
{
......@@ -80,6 +91,15 @@ namespace FLY.OBJComponents.Server
sqliteHelper.QueryTranAsync(sqls);
Count += lcs.Count();
BufferChanged?.Invoke(this, new NotifyBufferChangedEventArgs<TLc>()
{
Action = NotifyBufferChangedAction.Add,
EndingID = NewestID,
Count = lcs.Count(),
Items = lcs,
BufferCount = Count,
BufferNewestID = NewestID
});
}
/// <summary>
/// 清空全部数据
......@@ -91,6 +111,14 @@ namespace FLY.OBJComponents.Server
sqls.Add($"DELETE FROM {dbTable.TableName}");
sqliteHelper.QueryTranAsync(sqls);
Count = 0;
BufferChanged?.Invoke(this, new NotifyBufferChangedEventArgs<TLc>()
{
Action = NotifyBufferChangedAction.Reset,
EndingID = -1,
Count = 0,
BufferCount = Count,
BufferNewestID = NewestID
});
}
/// <summary>
......@@ -188,9 +216,19 @@ namespace FLY.OBJComponents.Server
sqliteHelper.QueryTranAsync(sqls);
Count++;
BufferChanged?.Invoke(this, new NotifyBufferChangedEventArgs<TDb>()
{
Action = NotifyBufferChangedAction.Add,
EndingID = NewestID,
Count = 1,
BufferCount = Count,
BufferNewestID = NewestID
});
}
public void AddRange(IEnumerable<TDb> dbs)
{
if (dbs.Count() == 0)
return;
List<string> sqls = new List<string>();
foreach (var db in dbs)
{
......@@ -203,6 +241,14 @@ namespace FLY.OBJComponents.Server
sqliteHelper.QueryTranAsync(sqls);
Count += dbs.Count();
BufferChanged?.Invoke(this, new NotifyBufferChangedEventArgs<TDb>()
{
Action = NotifyBufferChangedAction.Add,
EndingID = NewestID,
Count = dbs.Count(),
BufferCount = Count,
BufferNewestID = NewestID
});
}
/// <summary>
/// 清空全部数据
......@@ -214,6 +260,14 @@ namespace FLY.OBJComponents.Server
sqls.Add($"DELETE FROM {dbTable.TableName}");
sqliteHelper.QueryTranAsync(sqls);
Count = 0;
BufferChanged?.Invoke(this, new NotifyBufferChangedEventArgs<TDb>()
{
Action = NotifyBufferChangedAction.Reset,
EndingID = -1,
Count = 0,
BufferCount = Count,
BufferNewestID = NewestID
});
}
/// <summary>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment