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 { /// <summary> /// IBuffer<T>的观察窗口 /// /// </summary> public class BufferWindow<T> : INotifyPropertyChanged, IDisposable { public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// IBuffer<T> /// </summary> public IBuffer<T> Buffer; #region property /// <summary> /// 最后一行数据的ID /// </summary> public int RecordLastID { get; private set; } = 0; /// <summary> /// 窗口最后一行的目标ID /// </summary> public int WindowID { get; private set; } /// <summary> /// 窗口大小 /// </summary> public int Size { get; set; } = 30; /// <summary> /// buffer 的总页数 /// </summary> public int TotalPages { get; private set; } /// <summary> /// 当前页码 /// </summary> public int CurrentPage { get; private set; } /// <summary> /// 保持最新,改变WindowID 无效 /// </summary> public bool IsKeepNewest { get; private set; } /// <summary> /// 最后一页 /// </summary> public bool IsLastPage { get; private set; } /// <summary> /// 最前一页 /// </summary> public bool IsFirstPage { get; private set; } #endregion /// <summary> /// 窗口中的数据 /// </summary> public ObservableCollection<T> Record { get; } = new ObservableCollection<T>(); public BufferWindow(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") { 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<T> getRecordReponse = retData as GetRecordReponse<T>; if (getRecordReponse.Items != null) { WindowID = getRecordReponse.LastID; push(getRecordReponse.LastID, getRecordReponse.Items); } }, null); } else { Buffer.GetRecord(WindowID, 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 newEndingIndex = e.StartingIndex - 1 + 1; int nFirstID = e.StartingIndex; int nLastID = newEndingIndex; if (IsKeepNewest)//保持数据最新 { WindowID = newEndingIndex; } int wLastID = WindowID; //以 nFirstID 为0 偏移 int offset = -nFirstID; wLastID += offset; nLastID += offset; if (wLastID < -1) { //新数据不用添加到Record } else { push(newEndingIndex, (IList<T>)e.Items); } } break; case NotifyBufferChangedAction.Replace: { int newEndingIndex = e.StartingIndex - 1 + 1; push(newEndingIndex, (IList<T>)e.Items); } break; case NotifyBufferChangedAction.Remove: { int newEndingIndex = e.StartingIndex - 1 + 1; remove(newEndingIndex, 1); } break; case NotifyBufferChangedAction.Reset: { //数据清空 Record.Clear(); RecordLastID = 0; WindowID = Size - 1; } 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; rFirstID = 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; rFirstID = 0; if (lastID <= -1)//被删除数据在当前数据前面,什么都不用做 { return; } else //被删除数据与当前数据有交集 { //重新问buffer获取当前数据块 Record.Clear(); RecordLastID = 0; 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() { int firstID = Buffer.NewestID - Buffer.Count + 1; int lastID = Buffer.NewestID; int wLastID = WindowID; int offset = -firstID; lastID += offset; wLastID += offset; firstID = 0; int page = (int)(Math.Ceiling(1.0 * wLastID / Size)); TotalPages = page + (int)(Math.Ceiling((1.0 * (lastID - wLastID) / Size))); CurrentPage = page; if (CurrentPage <=1) IsFirstPage = true; else IsFirstPage = false; if (CurrentPage >= TotalPages) IsLastPage = true; else IsLastPage = false; } #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() { } } }