BufferPage.cs 12.9 KB
Newer Older
潘栩锋's avatar
潘栩锋 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
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
    {
19 20
        const int MARKNO_UPDATE_GCURRPAGE = 1;

潘栩锋's avatar
潘栩锋 committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
        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;
38
       
潘栩锋's avatar
潘栩锋 committed
39 40 41 42 43

        /// <summary>
        /// 保持最新,改变WindowID 无效,它是输入
        /// </summary>
        public bool IsKeepNewest { get; private set; }
44

潘栩锋's avatar
潘栩锋 committed
45
        /// <summary>
46
        /// 当前全局页码,GCurrPage*Size 就是页码第1行的ID
潘栩锋's avatar
潘栩锋 committed
47
        /// </summary>
48
        public int GCurrPage { get; set; }
潘栩锋's avatar
潘栩锋 committed
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69

        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>
70
        public int TotalPages => GPageLast - GPage1st + 1;
潘栩锋's avatar
潘栩锋 committed
71 72 73
        /// <summary>
        /// 当前页码, 页码从1-TotalPages
        /// </summary>
74
        public int CurrentPage => GCurrPage - GPage1st + 1;
潘栩锋's avatar
潘栩锋 committed
75 76 77 78 79 80 81 82 83

        /// <summary>
        /// 最后一页
        /// </summary>
        public bool IsLastPage => (CurrentPage >= TotalPages);
        /// <summary>
        /// 最前一页
        /// </summary>
        public bool IsFirstPage => (CurrentPage <= 1);
84 85 86

        public int GPage1st { get; private set; }
        public int GPageLast { get; private set; }
潘栩锋's avatar
潘栩锋 committed
87 88 89 90 91 92 93 94 95 96 97
        #endregion



        public BufferPage(IBuffer<T> buffer, int size = 30)
        {
            Size = size;
            Buffer = buffer;

            IsKeepNewest = true;
            updatePageInfo();
98
            updateGCurrPage();
潘栩锋's avatar
潘栩锋 committed
99 100 101 102 103 104 105 106 107 108 109 110
            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();
111
                updateGCurrPage();
潘栩锋's avatar
潘栩锋 committed
112 113 114 115
                GetWindow();
            }
        }

116 117 118 119 120 121
        

        /// <summary>
        /// GCurrPage 肯定在合理位置
        /// Buffer.Count 肯定大于0
        /// </summary>
潘栩锋's avatar
潘栩锋 committed
122 123
        void GetWindow()
        {
124 125
            int firstId = GCurrPage * Size;
            int lastId = firstId + Size - 1;
潘栩锋's avatar
潘栩锋 committed
126

127 128 129 130 131 132
            int Buffer1stId = Buffer.NewestID - Buffer.Count + 1;
            if (firstId < Buffer1stId)
                firstId = Buffer1stId;
            
            if (lastId > Buffer.NewestID)
                lastId = Buffer.NewestID;
潘栩锋's avatar
潘栩锋 committed
133

134 135 136

            int size = lastId - firstId + 1;
            Buffer.GetRecord(lastId, size, (asyncContext, retData) =>
潘栩锋's avatar
潘栩锋 committed
137
            {
138 139 140
                GetRecordReponse<T> getRecordReponse = retData as GetRecordReponse<T>;
                if (getRecordReponse.Items != null)
                    push(getRecordReponse.LastID, getRecordReponse.Items);
潘栩锋's avatar
潘栩锋 committed
141

142
            }, null);
潘栩锋's avatar
潘栩锋 committed
143

144
            
潘栩锋's avatar
潘栩锋 committed
145 146 147 148 149 150 151 152
        }

        private void Buffer_PropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            if ((e.PropertyName == "Count") ||
                (e.PropertyName == "NewestID"))
            {
                updatePageInfo();
153 154 155 156 157 158 159 160 161 162 163
                

                FObjBase.PollModule.Current.Poll_JustOnce(() =>
                {
                    if (updateGCurrPage()) 
                    {
                        GetWindow();
                    }


                }, this, MARKNO_UPDATE_GCURRPAGE);
潘栩锋's avatar
潘栩锋 committed
164 165 166 167 168 169 170 171
            }
        }

        private void Buffer_BufferChanged(object sender, NotifyBufferChangedEventArgs<T> e)
        {
            switch (e.Action)
            {
                case NotifyBufferChangedAction.Add:
172
                case NotifyBufferChangedAction.Replace:
潘栩锋's avatar
潘栩锋 committed
173
                    {
174
                        //判断添加的数据是否在当前窗口内
潘栩锋's avatar
潘栩锋 committed
175 176 177 178
                        int newEndingID = e.EndingID;
                        int nFirstID = e.EndingID;
                        int nLastID = newEndingID;

179 180
                        int wFirstID = GCurrPage * Size;
                        int wLastID = wFirstID + Size - 1;
潘栩锋's avatar
潘栩锋 committed
181

182 183 184 185
                        if (wFirstID<nLastID)
                            return;//什么都不用干
                        if(wLastID<nFirstID)
                            return;//什么都不用干
潘栩锋's avatar
潘栩锋 committed
186

187 188
                        //有交集把数据放入
                        push(newEndingID, (IList<T>)e.Items);
潘栩锋's avatar
潘栩锋 committed
189 190 191 192
                    }
                    break;
                case NotifyBufferChangedAction.Remove:
                    {
193
                        remove(e.EndingID, e.Count);
潘栩锋's avatar
潘栩锋 committed
194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294
                    }
                    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;
295
                FitRecord(firstID, lastID);
潘栩锋's avatar
潘栩锋 committed
296 297 298 299 300 301 302 303
            }
        }

        /// <summary>
        /// 把多出window范围的数据删除
        /// </summary>
        void FitWindow()
        {
304 305 306 307 308 309
            int wFirstID = GCurrPage * Size;
            int wLastID = wFirstID + Size - 1;
            FitRecord(wFirstID, wLastID);
        }
        void FitRecord(int firstID, int lastID)
        { 
潘栩锋's avatar
潘栩锋 committed
310 311 312
            int rFirstID = RecordLastID - Record.Count() + 1;
            int rLastID = RecordLastID;

313
            //删除交集以外的数据
潘栩锋's avatar
潘栩锋 committed
314

315
            if (rFirstID < firstID)
潘栩锋's avatar
潘栩锋 committed
316
            {
317 318 319 320 321 322 323 324 325 326 327 328 329
                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);
                }
潘栩锋's avatar
潘栩锋 committed
330
            }
331 332

            if (rLastID > lastID)
潘栩锋's avatar
潘栩锋 committed
333
            {
334 335
                int remove_cnt = rLastID - lastID;
                if (remove_cnt >= Record.Count())
潘栩锋's avatar
潘栩锋 committed
336
                {
337 338 339
                    //全部删除
                    Record.Clear();
                    RecordLastID = -1;
潘栩锋's avatar
潘栩锋 committed
340 341 342 343
                    return;
                }
                else
                {
344
                    for (int i = 0; i < remove_cnt; i++)
潘栩锋's avatar
潘栩锋 committed
345
                        Record.RemoveAt(Record.Count() - 1);
346
                    RecordLastID = lastID;
潘栩锋's avatar
潘栩锋 committed
347 348 349 350 351 352 353 354 355
                }
            }
        }

        void updatePageInfo()
        {
            if (Buffer.Count == 0)
            {
                //没有数据
356 357
                GPage1st = 0;
                GPageLast = -1;
潘栩锋's avatar
潘栩锋 committed
358 359
                return;
            }
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
            
            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;
            }
潘栩锋's avatar
潘栩锋 committed
387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409
        }
        #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;
410 411
            if(updateGCurrPage())
                GetWindow();
潘栩锋's avatar
潘栩锋 committed
412 413 414 415 416 417 418 419 420 421 422
        }
        /// <summary>
        /// 移动到某页
        /// </summary>
        /// <param name="page"></param>
        public void MovePage(int page)
        {
            if (CurrentPage != page)
            {
                if ((page <= TotalPages) && (page > 0))
                {
423 424
                    GCurrPage = page + GPage1st - 1;
                    IsKeepNewest = (GCurrPage == GPageLast);
潘栩锋's avatar
潘栩锋 committed
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
                    GetWindow();
                }
            }
        }

        #endregion
        /// <summary>
        /// 释放窗口,数据不再更新
        /// </summary>
        public void Dispose()
        {

        }
    }
}