在線演示地址:Silverlight+WCF 新手實例 象棋 在線演示
這節開始,標題裏就去掉"迴歸WCF通訊應用"幾字了。
上節我們成功實現了進入房間,服務端也收到用戶進入房間的請求了,這節,我們服務端收到進入房間請求後,通知在房間大門外的人更新房間狀態。
我們要增加一個回調方法,ICallBack接口那,忘記的人回去看看WCF通訊那幾篇(十四到十七節)。
方法如下,以前說過了,回調的方法是給客戶端實現的,服務端只管調就行了:
namespace GameService
{
interface ICallBack
{
[OperationContract(IsOneWay = true )]
void NotifyRoomUpdate(Room room);
}
}
那我們回到服務端進入房間的代碼,只管調用一下了:
我們看下這段進入房間代碼:
{
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,代碼如下:
{
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下]:
{
/// <summary>
/// 通知 by 路過秋天
/// </summary>
public class Notify
{
}
}
我們添加一個新方法,叫Room, 我們把那foreach的方法Copy過來,就是如下代碼了:
{
/// <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那了,我們要更新房間的狀態的。
{
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方法來了。
{
// 這裏實現啦
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方法,就兩行代碼了,大夥別急:
{
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頁面還沒東西呢。