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 { const int MARKNO_UPDATE_GCURRPAGE = 1; 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> /// 当前全局页码,GCurrPage*Size 就是页码第1行的ID /// </summary> public int GCurrPage { get; 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 => GPageLast - GPage1st + 1; /// <summary> /// 当前页码, 页码从1-TotalPages /// </summary> public int CurrentPage => GCurrPage - GPage1st + 1; /// <summary> /// 最后一页 /// </summary> public bool IsLastPage => (CurrentPage >= TotalPages); /// <summary> /// 最前一页 /// </summary> public bool IsFirstPage => (CurrentPage <= 1); public int GPage1st { get; private set; } public int GPageLast { get; private set; } #endregion public BufferPage(IBuffer<T> buffer, int size = 30) { Size = size; Buffer = buffer; IsKeepNewest = true; updatePageInfo(); updateGCurrPage(); 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(); updateGCurrPage(); GetWindow(); } } /// <summary> /// GCurrPage 肯定在合理位置 /// Buffer.Count 肯定大于0 /// </summary> void GetWindow() { int firstId = GCurrPage * Size; int lastId = firstId + Size - 1; int Buffer1stId = Buffer.NewestID - Buffer.Count + 1; if (firstId < Buffer1stId) firstId = Buffer1stId; if (lastId > Buffer.NewestID) lastId = Buffer.NewestID; 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(); FObjBase.PollModule.Current.Poll_JustOnce(() => { if (updateGCurrPage()) { GetWindow(); } }, this, MARKNO_UPDATE_GCURRPAGE); } } private void Buffer_BufferChanged(object sender, NotifyBufferChangedEventArgs<T> e) { switch (e.Action) { case NotifyBufferChangedAction.Add: case NotifyBufferChangedAction.Replace: { //判断添加的数据是否在当前窗口内 int newEndingID = e.EndingID; int nFirstID = e.EndingID; int nLastID = newEndingID; int wFirstID = GCurrPage * Size; int wLastID = wFirstID + Size - 1; if (wFirstID<nLastID) return;//什么都不用干 if(wLastID<nFirstID) return;//什么都不用干 //有交集把数据放入 push(newEndingID, (IList<T>)e.Items); } break; case NotifyBufferChangedAction.Remove: { remove(e.EndingID, e.Count); } break; case NotifyBufferChangedAction.Reset: { //数据清空 Record.Clear(); RecordLastID = 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; FitRecord(firstID, lastID); } } /// <summary> /// 把多出window范围的数据删除 /// </summary> void FitWindow() { int wFirstID = GCurrPage * Size; int wLastID = wFirstID + Size - 1; FitRecord(wFirstID, wLastID); } void FitRecord(int firstID, int lastID) { int rFirstID = RecordLastID - Record.Count() + 1; int rLastID = RecordLastID; //删除交集以外的数据 if (rFirstID < firstID) { int remove_cnt = firstID - rFirstID; if (remove_cnt >= Record.Count()) { //全部删除 Record.Clear(); RecordLastID = -1; return; } else { for (int i = 0; i < remove_cnt; i++) Record.RemoveAt(0); } } if (rLastID > lastID) { int remove_cnt = rLastID - lastID; if (remove_cnt >= Record.Count()) { //全部删除 Record.Clear(); RecordLastID = -1; return; } else { for (int i = 0; i < remove_cnt; i++) Record.RemoveAt(Record.Count() - 1); RecordLastID = lastID; } } } void updatePageInfo() { if (Buffer.Count == 0) { //没有数据 GPage1st = 0; GPageLast = -1; return; } GPage1st = (Buffer.NewestID - (Buffer.Count - 1)) / Size; GPageLast = Buffer.NewestID / Size; } bool updateGCurrPage() { int gCurrPage = GCurrPage; if (IsKeepNewest) { gCurrPage = GPageLast; } else { if (GCurrPage < GPage1st) gCurrPage = GPage1st; else if (GCurrPage > GPageLast) gCurrPage = GPageLast; } if (gCurrPage != GCurrPage) { GCurrPage = gCurrPage; return true; } else { return false; } } #region 窗口移动 /// <summary> /// 下一页, 让窗口向后移,TailerID+=Capacity /// </summary> public void MoveNextPage() { MovePage(CurrentPage + 1); } /// <summary> /// 上一页,让窗口向前移,TailerID-=Capacity /// </summary> public void MovePrePage() { MovePage(CurrentPage - 1); } /// <summary> /// 移动到最新数据 /// </summary> public void MoveNewest() { IsKeepNewest = true; if(updateGCurrPage()) GetWindow(); } /// <summary> /// 移动到某页 /// </summary> /// <param name="page"></param> public void MovePage(int page) { if (CurrentPage != page) { if ((page <= TotalPages) && (page > 0)) { GCurrPage = page + GPage1st - 1; IsKeepNewest = (GCurrPage == GPageLast); GetWindow(); } } } #endregion /// <summary> /// 释放窗口,数据不再更新 /// </summary> public void Dispose() { } } }