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; namespace FLY.OBJComponents.Client { /// /// IBuffer的观察窗口 /// /// public class BufferWindow : INotifyPropertyChanged, IDisposable { public event PropertyChangedEventHandler PropertyChanged; /// /// IBuffer /// public IBuffer Buffer; #region property /// /// 最新数据的ID,就是 Buffer.NewestID, /// 但不直接使用Buffer.NewestID,因为 Buffer.NewestID可能与接收的数据滞后,或超前 /// public int RecordLastID { get; private set; } = -1; /// /// 窗口最后一行的目标ID /// public int WindowID { get; private set; } /// /// 窗口大小 /// public int Size { get; set; } = 30; /// /// buffer 的总页数 /// public int TotalPages { get; private set; } /// /// 当前页码, 页码从1-TotalPages /// public int CurrentPage { get; private set; } /// /// 保持最新,改变WindowID 无效 /// public bool IsKeepNewest { get; private set; } /// /// 最后一页 /// public bool IsLastPage { get; private set; } /// /// 最前一页 /// public bool IsFirstPage { get; private set; } #endregion /// /// 窗口中的数据 /// public ObservableCollection Record { get; } = new ObservableCollection(); public BufferWindow(IBuffer 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") { if (Size < 10) Size = 10; updatePageInfo(); GetWindow(); } else if (e.PropertyName == "WindowID") { updatePageInfo(); } else if (e.PropertyName == "IsKeepNewest") { } } void GetWindow() { if (IsKeepNewest) { Buffer.GetRecord(Size, (asyncContext, retData) => { GetRecordReponse getRecordReponse = retData as GetRecordReponse; if (getRecordReponse.Items != null) { WindowID = getRecordReponse.LastID; push(getRecordReponse.LastID, getRecordReponse.Items); } }, null); } else { Buffer.GetRecord(WindowID, Size, (asyncContext, retData) => { GetRecordReponse getRecordReponse = retData as GetRecordReponse; 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 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)e.Items); } } break; case NotifyBufferChangedAction.Replace: { push(e.EndingID, (IList)e.Items); } break; case NotifyBufferChangedAction.Remove: { remove(e.EndingID, 1); } break; case NotifyBufferChangedAction.Reset: { //数据清空 Record.Clear(); RecordLastID = -1; WindowID = Size - 1; } break; case NotifyBufferChangedAction.IsConnected: { //重新连接上服务器,获取全部数据 GetWindow(); } break; } } void push(int items_lastID, IList 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(); } } } /// /// 把多出window范围的数据删除 /// 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() { int firstID = Buffer.NewestID - (Buffer.Count - 1); int lastID = Buffer.NewestID; int wLastID = WindowID; //修正后,firstID,lastID 就是Buffer 内部数据量的排序,lastID=Count-1 int offset = -firstID; lastID += offset; wLastID += offset; firstID = 0; int page = wLastID / Size; int page1st_size = wLastID % Size; int totalpages = (int)(Math.Ceiling((1.0 * (lastID - page1st_size) / Size))); if (page1st_size != 0) { page++; totalpages++; } CurrentPage = page; TotalPages = totalpages; if (CurrentPage <=1) IsFirstPage = true; else IsFirstPage = false; if (CurrentPage >= TotalPages) IsLastPage = true; else IsLastPage = false; } #region 窗口移动 /// /// 下一页, 让窗口向后移,TailerID+=Capacity /// public void MoveNextPage() { IsKeepNewest = false; MovePage(CurrentPage + 1); } /// /// 上一页,让窗口向前移,TailerID-=Capacity /// public void MovePrePage() { IsKeepNewest = false; MovePage(CurrentPage - 1); } /// /// 移动到最新数据 /// public void MoveNewest() { IsKeepNewest = true; GetWindow(); } /// /// 移动到某页 /// /// public void MovePage(int page) { if (CurrentPage != page) { if ((page <= TotalPages) && (page > 0)) { WindowID += Size * (page - CurrentPage); GetWindow(); } } } /// /// 通过 最后数据的ID,移动 /// /// public void Move(int lastID) { IsKeepNewest = false; WindowID = lastID; GetWindow(); } #endregion /// /// 释放窗口,数据不再更新 /// public void Dispose() { } } }