2010-02-06 51 views
5

我正在爲學校寫一個簡單的tic tac toe遊戲。這個任務是用C++編寫的,但是老師讓我有權使用C#和WPF作爲挑戰。我已經完成了所有的遊戲邏輯並且表格大部分完成了,但是我碰到了一堵牆。我目前正在使用Label來表明是誰輪到它,並且我想在玩家進行有效移動時更改它。根據Applications = Code + Markup,我應該可以使用Window類的FindName方法。但是,它不斷返回null。代碼如下:FindName返回null

public TicTacToeGame() 
{ 
    Title = "TicTacToe"; 
    SizeToContent = SizeToContent.WidthAndHeight; 
    ResizeMode = ResizeMode.NoResize; 

    UniformGrid playingField = new UniformGrid(); 
    playingField.Width = 300; 
    playingField.Height = 300; 
    playingField.Margin = new Thickness(20); 

    Label statusDisplay = new Label(); 
    statusDisplay.Content = "X goes first"; 
    statusDisplay.FontSize = 24; 
    statusDisplay.Name = "StatusDisplay"; // This is the name of the control 
    statusDisplay.HorizontalAlignment = HorizontalAlignment.Center; 
    statusDisplay.Margin = new Thickness(20); 

    StackPanel layout = new StackPanel(); 
    layout.Children.Add(playingField); 
    layout.Children.Add(statusDisplay); 

    Content = layout; 

    for (int i = 0; i < 9; i++) 
    { 
     Button currentButton = new Button(); 
     currentButton.Name = "Space" + i.ToString(); 
     currentButton.FontSize = 32; 
     currentButton.Click += OnPlayLocationClick; 

     playingField.Children.Add(currentButton); 
    } 

    game = new TicTacToe.GameCore(); 
} 

void OnPlayLocationClick(object sender, RoutedEventArgs args) 
{ 
    Button clickedButton = args.Source as Button; 

    int iButtonNumber = Int32.Parse(clickedButton.Name.Substring(5,1)); 
    int iXPosition = iButtonNumber % 3, 
     iYPosition = iButtonNumber/3; 

    if (game.MoveIsValid(iXPosition, iYPosition) && 
     game.Status() == TicTacToe.GameCore.GameStatus.StillGoing) 
    { 
     clickedButton.Content = 
      game.getCurrentPlayer() == TicTacToe.GameCore.Player.X ? "X" : "O"; 
     game.MakeMoveAndChangeTurns(iXPosition, iYPosition); 

     // And this is where I'm getting it so I can use it. 
     Label statusDisplay = FindName("StatusDisplay") as Label; 
     statusDisplay.Content = "It is " + 
      (game.getCurrentPlayer() == TicTacToe.GameCore.Player.X ? "X" : "O") + 
      "'s turn"; 
    } 
} 

這是怎麼回事?我在兩個地方都使用了相同的名稱,但FindName找不到它。我嘗試過使用Snoop來查看層次結構,但表單不顯示在可供選擇的應用程序列表中。我在StackOverflow上搜索,發現我should be able to use VisualTreeHelper class,但我不明白如何使用它。

任何想法?

回答

6

FindName在調用控件的XAML名稱範圍上操作。就你而言,由於控件完全在代碼中創建,因此XAML名稱範圍是空的 - 這就是爲什麼FindName失敗。見this page

初始加載和處理後的任何增加的元素樹必須調用相應的執行RegisterName用於定義XAML名稱範圍的類。否則,添加的對象不能通過諸如FindName之類的方法按名稱引用。僅僅設置Name屬性(或x:Name Attribute)不會將該名稱註冊到任何XAML名稱範圍內。

解決問題的最簡單方法是將類的StatusDisplay標籤的引用作爲私有成員存儲在類中。或者,如果您想了解如何使用VisualTreeHelper類,那麼可以使用代碼片段at the bottom of this page來引導可視化樹來查找匹配的元素。

(編輯:當然,它的工作少打電話RegisterName比使用VisualTreeHelper,如果你不想存儲到標籤的參考。)

我建議你閱讀的第一個鏈接如果您計劃在任何深度使用WPF/Silverlight,那麼這是完整的。有用的信息有。

+0

我選擇了這個程序,與私人成員一起去。感謝您的解釋,我會盡快閱讀完整頁面。 – 2010-02-06 22:04:08

2

你必須爲你的窗口的新名稱範圍:

NameScope.SetNameScope(this, new NameScope()); 

然後你註冊窗口的標籤名稱:

RegisterName(statusDisplay.Name, statusDisplay); 

因此,這似乎是所有你需要做的使FindName()工作。