在线演示地址:Silverlight+WCF 新手实例 象棋 在线演示
这节,我们要实现棋谱列界面布局和棋谱的获取,先上一张久远的图片:

看清楚了,到本节为止,除了第三区棋谱区,其它的区域我们都已完成了,所以,我们抓紧时间,赶紧吧:
好了,先布局,和以往一样:
1:界面拖一个Border到Index.xaml,到第三区的位置,设置好宽和高[212*602]:
<
UserControl ...省略... d:DesignHeight
=
"
620
"
d:DesignWidth
=
"
1000
"
>
<
Grid x:Name
=
"
LayoutRoot
"
Background
=
"
White
"
>
//
...省略之前四个Border...
<
Border BorderBrush
=
"
Silver
"
BorderThickness
=
"
1
"
Height
=
"
602
"
HorizontalAlignment
=
"
Left
"
Margin
=
"
538,12,0,0
"
Name
=
"
chessManualBoard
"
VerticalAlignment
=
"
Top
"
Width
=
"
212
"
/>
</
Grid
>
</
UserControl
>
2:新建一个用户控件:就叫:ChessManual.xaml
3:后台动态加载控件了,后台代码就两行,看今天新加的那
public
partial
class
Index : UserControl
{
//
..省略N行...
ChessManual chessManualControl;
public
Index()
{
//
..省略N行...
chessManualControl
=
new
ChessManual();
//
今天新加的
chessManualBoard.Child
=
chessManualControl;
//
..省略N行...
}
//
..省略N行...
}
OK,控件加载完了。接下来的任务就是要实现ChessManual控件里的内容显示了:
4:接下来我们回到ChessManual.xaml里,改一下总体宽和高为212*602:
<
UserControl ...省略一堆... d:DesignHeight
=
"
602
"
d:DesignWidth
=
"
212
"
>
<
Grid x:Name
=
"
LayoutRoot
"
Background
=
"
White
"
>
</
Grid
>
</
UserControl
>
我们往里添加界面布局:
<
Grid
x:Name
="LayoutRoot"
Background
="White"
>
<
ListBox
Height
="520"
HorizontalAlignment
="Left"
Name
="lbChessManual"
VerticalAlignment
="Top"
Width
="190"
Margin
="10,10,0,0"
/>
<
Button
Content
="回放"
Height
="23"
HorizontalAlignment
="Right"
Margin
="0,541,12,0"
Name
="btnPlay"
VerticalAlignment
="Top"
Width
="53"
/>
<
Slider
Height
="23"
HorizontalAlignment
="Left"
Margin
="12,541,0,0"
Name
="slPlayerInternal"
VerticalAlignment
="Top"
Width
="56"
SmallChange
="0.5"
Maximum
="9"
LargeChange
="1"
/>
<
TextBox
IsEnabled
="false"
Height
="23"
HorizontalAlignment
="Right"
Margin
="0,541,110,0"
Name
="txtValue"
Text
="0"
VerticalAlignment
="Top"
Width
="15"
/>
<
TextBlock
Height
="23"
HorizontalAlignment
="Center"
Margin
="108,545,70,34"
Name
="textBlock1"
Text
="秒/步"
VerticalAlignment
="Center"
Width
="34"
/>
</
Grid
>
代码看起来不整洁,是有点乱,布完局后的结果就是上面图的第三区了,不另外上图了:
至此,布局就完成了,接下来,我们要进入和棋谱相关的操作了服务端操作了:
在双方下棋的过程中,我们不断交互的传送棋步,同时,服务端也记录了每一步的棋步信息;
这节,我们将通过棋步生成棋谱,同时和棋步一起传递。
有一些基础知识要知道,就是棋谱是怎么写出来的?这个,大伙自己百度看看了,不做介绍了!
这里,我封装成一个方法,附加在Chess象棋类里面:
首先呢,棋谱里的数字,一方是数字,一方是中文数字,所以先来一个方法把数字转中文数字:
private string GetGBKNum(int num)
{
switch (num)
{
case 1:
return "一";
case 2:
return "二";
case 3:
return "三";
case 4:
return "四";
case 5:
return "五";
case 6:
return "六";
case 7:
return "七";
case 8:
return "八";
case 9:
return "九";
default:
return "XX";
}
}
有了这个方法,接着我们实现写棋谱:
//写棋谱
public string WriteManual(Chessman chessman, Point moveTo)
{
string manual = (chessman.Color == Colors.Red ? "红方:" : "黑方:") + chessman.Name;
int moveX = 9 - (int)chessman.MovePoint.X;
int toX = 9 - (int)moveTo.X;
int value = (int)chessman.MovePoint.Y - (int)moveTo.Y;
manual += chessman.Color == Colors.Red ? GetGBKNum(moveX) : moveX.ToString();
manual += value == 0 ? "平" : ((value > 0) ? "进" : "退");
if (value != 0)
{
switch (Action.Rule.GetChessTypeByName(chessman.Name))
{
case ChessType.Bing:
case ChessType.Che:
case ChessType.Jiang:
case ChessType.Pao:
toX = Math.Abs(value);
break;
}
}
manual += chessman.Color == Colors.Red ? GetGBKNum(toX) : toX.ToString();
return manual;
}
上面这段函数可能没那么好理解,大伙需要先理解棋谱的基础知识,才能好好的理解这段代码,不理解就直接使用跳过也行了;
反正一步棋就产生一行中文说明的棋谱信息。
有了写棋谱函数,我们在哪里使用呢?当然是回到我们提交棋步到服务端那时了,回到Chess.xaml.cs里:
void
Action_HelpMoveStepEvent(ChessNewInstance.Chessman chessman, Point moveTo)
{
MoveStep step
=
new
MoveStep();
step.FromX
=
chessman.MovePoint.X;
step.FromY
=
chessman.MovePoint.Y;
step.ToX
=
moveTo.X;
step.ToY
=
moveTo.Y;
step.ColorValue
=
chessman.Color
==
Colors.Red
?
1
:
2
;
step.Name
=
chess.WriteManual(chessman, moveTo);
//
这里只加一行代码
App.player.Step
=
step;
//
附加棋步
App.client.MoveStepAsync(App.player);
chess.IsCanMove
=
false
;
}
在这里,我们只添加了一行代码,把棋谱放到棋步的Name里面,然后随便棋步一起过去了。
OK,接着我们回到接收棋步的地方,同样的,我们收到棋步后,把棋步的Name显示到棋谱区就行了。
我们接收棋步是在Chess.xaml.cs里,可是我们要显示的棋谱区却在我们新添加的ChessManual.xaml里;
所以,我们需要在控件间传递消息,所以,我们又要请出委托了:
在Chess.xaml.cs里添加委托,添加两行,然后在接收到棋步的最后,调用一下就OK了,参数就是传递棋步了:
public
partial
class
Chess : UserControl
{
public
delegate
void
HelpSetChessManual(MoveStep step);
public
event
HelpSetChessManual HelpSetChessManualEvent;
ChessNewInstance.Chess chess;
//
这里我们同时把它提到全局对象
public
Chess()
{
//
...省略N行...
}
//
...省略N行...
void
client_NotifyMoveStepReceived(
object
sender, NotifyMoveStepReceivedEventArgs e)
{
if
(App.player.ID
!=
e.player.ID)
//
非自己
{
//
...省略N行...
}
HelpSetChessManualEvent(e.player.Step);
//
这里调用
}
//
...省略N行...
}
好了,我们的Index.xaml.cs又要干活了:
先和棋谱控件约好接口调用先,所以我们在棋谱区添加一个方法:
代码
public
partial
class
ChessManual : UserControl
{
public
ChessManual()
{
InitializeComponent();
}
public
void
Add(GameService.MoveStep step)
{
lbChessManual.Items.Add(step.ID
+
"
:
"
+
step.Name);
lbChessManual.SelectedIndex
=
lbChessManual.Items.Count
-
1
;
lbChessManual.UpdateLayout();
lbChessManual.ScrollIntoView(lbChessManual.SelectedItem);
}
}
是不是发现和Chat聊天区的极其相似,其实就是代码Copy一下,改改名称也就是了。
好了,接口也有了,我们回到Index.xaml.cs里做一下功夫:
public
partial
class
Index : UserControl
{
//
...省略N行...
public
Index()
{
//
...省略N行...
chessControl.HelpSetChessManualEvent += new Chess.HelpSetChessManual(chessControl_HelpSetChessManualEvent);
}
void
chessControl_HelpSetChessManualEvent(GameService.MoveStep step)
{
chessManualControl.Add(step);
}
//
...省略N行...
}
OK,至此,我们布局完了,写谱也有了,接谱也有了,该F5看下效果了:
一切正常,上图:

看到了吧,双方每走一步都有棋谱显示,只是棋谱,我们还没完?观众进来时,怎么还原棋谱?棋谱又该怎么回放?我们下节解说
本节就点到为止。