Silverlight+WCF 新手實例 象棋 房間狀態更新(二十)

在線演示地址:Silverlight+WCF 新手實例 象棋 在線演示

 

這節開始,標題裏就去掉"迴歸WCF通訊應用"幾字了。

 

上節我們成功實現了進入房間,服務端也收到用戶進入房間的請求了,這節,我們服務端收到進入房間請求後,通知在房間大門外的人更新房間狀態。

我們要增加一個回調方法,ICallBack接口那,忘記的人回去看看WCF通訊那幾篇(十四到十七節)。

方法如下,以前說過了,回調的方法是給客戶端實現的,服務端只管調就行了:

using  System.ServiceModel;

namespace  GameService
{
    
interface  ICallBack
    {
        [OperationContract(IsOneWay 
=   true )]
        
void  NotifyRoomUpdate(Room room);
    }
}

 

那我們回到服務端進入房間的代碼,只管調用一下了:

我們看下這段進入房間代碼:

05233822_AfoN.gif
  public   bool  EnterRoom(Player player,  int  roomID)
        {
            
bool  roomInDic  =  roomList.ContainsKey(roomID); // 房間列表裏有沒有
            Room room  =  roomInDic  ?  roomList[roomID] :  new  Room(); // 有就直接拿了,沒有就直接New一個新的
             if  ( ! room.RedInChair) // 房間的紅色座位有沒有人
            {
                room.RedInChair 
=  player.ColorValue  ==   1 ;
            }
            
if  ( ! room.BlackInChair) // 房間的黑色座位有沒有人
            {
                room.BlackInChair 
=  player.ColorValue  ==   2 ;
            }
            
if  ( ! roomInDic) // 房間列表裏沒有,添加到房間列表中
            {
                room.ID 
=  roomID;
                roomList.Add(roomID, room);
            }
            
            ChangeRoom(player, roomID);
// 改變玩家的房間標記,待會實現

            
// 這裏是新加的,通知0房間的人[未進入房間的人]都更新此房間狀態
             foreach  (KeyValuePair < Guid,Player >  item  in  playerList[ 0 ])
            {
                item.Value.CallBack.NotifyRoomUpdate(room);
            }
            
return   true ;
        }

 

foreach之前的代碼是上節的了,這裏我們只增加了一個foreach來循環0房間的用戶,通知他們更新房間狀態。

同樣的,如果是退出房間,也要加一個foreach,代碼如下:

05233822_AfoN.gif
public   void  OutRoom(Player player,  int  roomID)
        {
            
if  (roomID  >   0 )
            {
                Room room 
=  roomList[roomID];
                
if  (player.ColorValue  ==   1 ) // 如果退出玩家是紅色座位
                {
                    room.RedInChair 
=   false ;
                }
                
if  (player.ColorValue  ==   2 ) // 如果退出玩家是紅色黑色座位
                {
                    room.BlackInChair 
=   false ;
                }
                ChangeRoom(player, 
0 ); // 改變玩家的房間標記,待會實現

                
// 這裏是新加的,通知0房間的人[未進入房間的人]都更新此房間狀態
                 foreach  (KeyValuePair < Guid, Player >  item  in  playerList[ 0 ])
                {
                    item.Value.CallBack.NotifyRoomUpdate(room);
                }

            }
        }

 

當我們看到同樣的代碼循環重複的出現的時候,我們會感到皮癢,我們得把它封裝起來,弄成一個小函數調用。

於是,我新建了一個Notify通知類。用於把所有的通知都集成到這裏來。

皮癢了,GameService項目裏新建一個類[示例源代碼裏會放到一個文件夾Notify下]:

namespace  GameService
{
    
///   <summary>
    
///  通知 by 路過秋天
    
///   </summary>
     public   class  Notify
    {

    }
}

 

我們添加一個新方法,叫Room, 我們把那foreach的方法Copy過來,就是如下代碼了:

05233822_AfoN.gif
namespace  GameService
{
    
///   <summary>
    
///  通知 by 路過秋天
    
///   </summary>
     public   class  Notify
    {
        
internal   static   void  Room(Dictionary < int , Dictionary < Guid, Player >>  playerList, Room room)
        {
            
// 這裏是新加的,通知0房間的人[未進入房間的人]都更新此房間狀態
             foreach  (KeyValuePair < Guid, Player >  item  in  playerList[ 0 ])
            {
                item.Value.CallBack.NotifyRoomUpdate(room);
            }
        }
    }
}

 

有了這個,我們回去把房間進入的和退出的foreach都改成Notify.Room(playerList,room);就OK了。

大夥自己改了,這裏不再貼代碼出來了。

 

成了,服務端寫完了,那客戶端要實現回調的方法的,我們編繹一下GameService項目,不編繹是不行的,我們加了接口,

客戶端得「更新服務引用」,

怎麼更新?以前截過圖的,回去看上一節:Silverlight+WCF 新手實例 象棋 迴歸WCF通訊應用-進入房間(十九)

好了,回客戶端了,回哪?當然回到Room.xmal那了,我們要更新房間的狀態的。

05233822_AfoN.gif
namespace  NewChessProject
{
    
public   partial   class  Room : UserControl
    {
        
public  Room()
        {
            InitializeComponent();
            Game game 
=   new  Game();
            game.CreateGameRoom(
30 );
            game.DrawIn(LayoutRoot);

            
// 這裏實現ICallBack的方法
            App.client.NotifyRoomUpdateReceived  +=   new  EventHandler < GameService.NotifyRoomUpdateReceivedEventArgs > (client_NotifyRoomUpdateReceived);
        }

        
void  client_NotifyRoomUpdateReceived( object  sender, GameService.NotifyRoomUpdateReceivedEventArgs e)
        {
            
// 看這裏看這裏,這裏實現啦
        }

    }
}

 

這裏等待服務端調用時,執行的方法了,現在實現了。

嘿嘿,皮又癢了,三行的代碼,又封裝出一個UpdateRoomState方法來了。

05233822_AfoN.gif
  void  client_NotifyRoomUpdateReceived( object  sender, GameService.NotifyRoomUpdateReceivedEventArgs e)
        {
            
// 這裏實現啦
             if  (game.GameRoomList  !=   null   &&  e.room  !=   null )
            {
                UpdateRoomState(e.room, game.GameRoomList[e.room.ID 
-   1 ]);
            }
        }
        
void  UpdateRoomState(GameService.Room gsRoom, GameRoom room)
        {
            room.RedPlayerInChair 
=  gsRoom.RedInChair;
            room.BlackPlayerInChair 
=  gsRoom.BlackInChair;
            room.ReDraw();
        }

 

最後還調用了room的ReDraw()方法。咦?room是沒這個方法的,沒有就加,咦什麼咦。

回到GameRoom.cs裏去,加個ReDraw方法,就兩行代碼了,大夥別急:

05233822_AfoN.gif
public   void  ReDraw()
{
redChair.Fill 
=   new  RadialGradientBrush(RedPlayerInChair  ?  Colors.Blue : Colors.Red, Colors.Transparent);
blackChair.Fill 
=   new  RadialGradientBrush(BlackPlayerInChair  ?  Colors.Blue : Colors.Black, Colors.Transparent);
}

 

OK,客戶端寫完了,我們F5運行看結果:

啓動一個瀏覽器,登陸後我們不動,同時複製地址,新開一個瀏覽器,也登陸進去如下圖:

好,我們點擊第二個瀏覽器進去第一個紅色房間:

看,第一個房間的狀態變了。至此,我們順利完成了房間狀態的通知更新。

那退出房間哪去了?別急,Index頁面還沒東西呢。

 

 

轉載於:https://my.oschina.net/secyaher/blog/274390