protected internal override void OnMessageReceived(ConversationMessage message)
 {
     if (message is FileDataMessage || message is SendItemsMessage)
     {
         //TODO 这个应该交给一个线程去做。
         receiver.QueueMessage(message);
     }
     else if (message is ConversationRecoverRequestMessage)
     {
         //对方发一个请求,问我正在接收哪些文件。如果我这一边已经异常退出了,那么其实我是没什么信息可以回给对方。
         RecoverSendItemsResponse resp = new RecoverSendItemsResponse();
         resp.SetItems(receiver.TransferringItem);
         PostMessage(resp);
     }
     else if (message is CancelItemMessage)
     {
         CancelItemMessage msg = message as CancelItemMessage;
         msg.Items.ForEach((o) =>
         {
             var cutItem = Items.FirstOrDefault(d => d.ID == o.ID);
             if (cutItem != null)
             {
                 cutItem.TransferState = TransferState.Canceled;
                 if (cutItem.Type == ItemType.Directory)
                 {
                     var dir = cutItem as DirItem;
                     if (dir != null)
                     {
                         receiver.ProcessReceiveListChildItems(dir);
                     }
                 }
             }
         });
     }
 }
        public void Cancel(List <Item> list)
        {
            var msg = new CancelItemMessage {
                Items = list
            };

            PostMessageAsync(msg);
        }
        public void Cancel(List <Item> list)
        {
            receiver.Remove(list);
            var msg = new CancelItemMessage();

            msg.Items = list;
            PostMessage(msg);
        }
        //TODO 需要思考一下,这层封装很多余。Items和Datas也是重复的。
        public void Cancel(List <Item> list)
        {
            holder.Remove(list);
            list.ForEach((i) =>
            {
                i.TransferState = TransferState.Canceled;
            });
            var msg = new CancelItemMessage();

            msg.Items = list;
            PostMessage(msg);
        }
        protected internal override void OnMessageReceived(ConversationMessage message)
        {
            if (message is GetItemsRecoverMessage)
            {
                //修改holder获取已经有进度的Item,seek到进度位置。其它的全都seek到0,然后重新Post holder.
                var sendItemRecoverResponse = message as RecoverSendItemsResponse;
                if (sendItemRecoverResponse == null)
                {
                    return;
                }
                var remoteItems = sendItemRecoverResponse.Items;
                //因为所有的item,都是传输完毕确认之后才删除的,所以只要检查已有item即可。
                sendHolder.Items.ForEach((localItem) =>
                {
                    if (localItem is ISeekable)
                    {
                        var localSeekable = localItem as ISeekable;
                        var remoteItem    = remoteItems.Find(i => i.ID == localItem.ID);
                        //TODO 文件夹怎么处理?还需要再想想。文件夹能Seek吗?不应该吧?
                        if (remoteItem == null)
                        {
                            localSeekable.SeekTo(0);
                        }
                        else
                        {
                            localSeekable.SeekTo(remoteItem.TransferredLength);
                        }
                    }
                });
                PostAsSendable(sendHolder);
            }
            else if (message is CancelItemMessage)
            {
                CancelItemMessage msg = message as CancelItemMessage;
                msg.Items.ForEach((o) =>
                {
                    var cutItem = Items.Find(d => d.ID == o.ID);
                    if (cutItem != null)
                    {
                        cutItem.TransferState = TransferState.Canceled;
                    }
                });

                sendHolder.Remove(msg.Items);
            }
        }
        protected internal override void OnMessageReceived(ConversationMessage message)
        {
            if (message is CancelItemMessage)
            {
                CancelItemMessage msg = message as CancelItemMessage;
                msg.Items.ForEach((o) =>
                {
                    var cutItem = Items.FirstOrDefault(d => d.ID == o.ID);
                    if (cutItem != null)
                    {
                        cutItem.TransferState = TransferState.Canceled;
                    }
                });

                holder.Remove(msg.Items);
            }
            else if (message is ConfirmItemMessage)
            {
                Debug.WriteLine("ConfirmedItem msg count=" + (confirmMsgCount++));
                var cm = message as ConfirmItemMessage;
                //若不复制,Confirmed中的移除动作报错。测试确认一下。
                var tmpProcessingList = new List <Item>(ProcessingItems);
                //Console.WriteLine("Received a confirm message itemid=" + cm.ItemID);
                var item = tmpProcessingList.Find(i => i.ID == cm.ItemID);
                if (item != null)
                {
                    //这个状态改变,会导致item从ProcessingItems中移除。
                    item.ForceComplete(TransferState.Confirmed);
                    //移除动作是在同一线程中,移除完毕会进入这里。
                    if (ProcessingItems.Count() == 0)
                    {
                        //应该还需要做这个检查,有可能存在没有正在处理的文件,但其他也没法送,或者状态不对的情况。
                        if (Items.All(o => o.TransferState == TransferState.Confirmed))
                        {
                            //所有文件成功发送完毕
                            Completed?.Invoke(this);
                        }
                        else
                        {
                            //该做什么?没有正在处理的Item,但也不是所有的Item状态都是Confirmed。出错了..., 如果给对方发了列表,对方马上就回复Confirm,也是0
                        }
                    }
                    else
                    {
                        if (tmpProcessingList.All(o => o.TransferState == TransferState.WaitConfirmTimeouted || o.TransferState == TransferState.Error))
                        {
                            //处理列表中的东西,都是出错 / 等待确认超时的,没办法再处理了。报告错误。上层如果要重新发送,可以到ProcessingItem里面去取。
                            //TODO 只需检查ProcessingItems即可。需要确认一个文件出错,或者等待确认超时,传递到父目录没有?
                            Errored?.Invoke(this);
                        }
                    }
                }
            }
            else if (message is ReceiveItemErrorMessage)
            {
                var rie  = message as ReceiveItemErrorMessage;
                var item = ProcessingItems.FirstOrDefault(i => i.ID == rie.ItemID);
                if (item == null)
                {
                    item = Items.Find(i => i.ID == rie.ID);
                }
                if (item != null)
                {
                    item.ErrorCode     = rie.ErrorCode;
                    item.TransferState = TransferState.Error;
                }
            }
        }