作為一個樣式如何使其在WPF使用的例子,,讓我們看一下TTT簡單的實現, 如示例5-1。
示例5-1
<!-- Window1.xaml -->
<Window
x:Class="TicTacToe.Window1"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Text="TicTacToe">
<!-- the black background lets the tic-tac-toe -->
<!-- crosshatch come through on the margins -->
<Grid Background="Black">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Margin="0,0,2,2" Grid.Row="0" Grid.Column="0" x:Name="cell00" />
<Button Margin="2,0,2,2" Grid.Row="0" Grid.Column="1" x:Name="cell01" />
<Button Margin="2,0,0,2" Grid.Row="0" Grid.Column="2" x:Name="cell02" />
<Button Margin="0,2,2,2" Grid.Row="1" Grid.Column="0" x:Name="cell10" />
<Button Margin="2,2,2,2" Grid.Row="1" Grid.Column="1" x:Name="cell11" />
<Button Margin="2,2,0,2" Grid.Row="1" Grid.Column="2" x:Name="cell12" />
<Button Margin="0,2,2,0" Grid.Row="2" Grid.Column="0" x:Name="cell20" />
<Button Margin="2,2,2,0" Grid.Row="2" Grid.Column="1" x:Name="cell21" />
<Button Margin="2,2,0,0" Grid.Row="2" Grid.Column="2" x:Name="cell22" />
</Grid>
</Window>
這個grid的外觀上排列了一組9個按鈕在一個3X3柵格的TTT單元中,在按鈕上 使用了頁面空白為了TTT的交叉線陰影。對游戲邏輯的一個簡單的實現,在xaml 後台代碼中,如示例5-2所示。
示例5-2
// Window1.xaml.cs
namespace TicTacToe {
public partial class Window1 : Window {
// Track the current player (X or O)
string currentPlayer;
// Track the list of cells for finding a winner etc.
Button[] cells;
public Window1( ) {
InitializeComponent( );
// Cache the list of buttons and handle their clicks
this.cells = new Button[] { this.cell00, this.cell01, };
foreach( Button cell in this.cells ) {
cell.Click += cell_Click;
}
// Initialize a new game
NewGame( );
}
// Wrapper around the current player for future expansion,
// e.g. updating status text with the current player
string CurrentPlayer {
get { return this.currentPlayer; }
set { this.currentPlayer = value; }
}
// Use the buttons to track game state
void NewGame( ) {
foreach( Button cell in this.cells ) {
cell.Content = null;
}
CurrentPlayer = "X";
}
void cell_Click(object sender, RoutedEventArgs e) {
Button button = (Button)sender;
// Don't let multiple clicks change the player for a cell
if( button.Content != null ) { return; }
// Set button content
button.Content = CurrentPlayer;
// Check for winner or a tie
if( HasWon(this.currentPlayer) ) {
MessageBox.Show("Winner!", "Game Over");
NewGame( );
return;
}
else if( TieGame( ) ) {
MessageBox.Show("No Winner!", "Game Over");
NewGame( );
return;
}
// Switch player
if( CurrentPlayer == "X" ) {
CurrentPlayer = "O";
}
else {
CurrentPlayer = "X";
}
}
// Use this.cells to find a winner or a tie
bool HasWon(string player) {}
bool TieGame( ) {}
}
}
我們的簡單TTT邏輯使用字符串代表玩家,使用按鈕來跟蹤游戲狀態。當點擊 任意一個按鈕時,我們將內容設置為字符串,用來象征當前玩家以及轉換玩家。 當游戲結束的時候,每一個按鈕上的內容都會被清除。游戲中的截圖如圖5-1。
圖5-1
注意到圖5-1中,grid的背景來自頁面的空白。這些空白差不多使grid看上去 像一個可繪制的TTT木板(雖然我們將來會做的更好)。然而,如果我們真的指 望模仿一個手繪的游戲,我們已經對按鈕上的字體大小做了設置,但並沒匹配到 線條的厚度。
一種修復這個問題的方法是為每一個按鈕對象設置字體和寬度,如示例5-3。
示例5-3
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell00" />
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell01" />
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell02" />
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell10" />
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell11" />
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell12" />
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell20" />
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell21" />
<Button FontSize="32" FontWeight=""Bold"…" x:Name="cell22" />
依照我的視覺敏感性,今天,雖然這樣做使得X的和O的外觀更好,一旦我以 後想改動它,我就要負責在9個獨立的地方改變這些屬性,這是重復性的努力— —違反了我的編碼敏感性。我寧願重制我的決定——為了以後的維護,將我的 TTT單元的外觀放在一個共同的地方。這是樣式派得上用場的地方。