2010-02-06 22 views
5

Estoy escribiendo un juego de tic tac toe para la escuela. La tarea está en C++, pero el maestro me ha dado permiso para usar C# y WPF como un desafío. He terminado toda la lógica del juego y la forma está casi completa, pero me he topado con un muro. Actualmente estoy usando un Label para indicar quién es el turno y quiero cambiarlo cuando un jugador realiza un movimiento válido. De acuerdo con Applications = Code + Markup, debería ser capaz de usar el método FindName de la clase Window. Sin embargo, sigue volviendo null. Aquí está el código:FindName return 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"; 
    } 
} 

¿Qué está pasando aquí? Estoy usando el mismo nombre en ambos lugares, pero FindName no puedo encontrarlo. Intenté usar Snoop para ver la jerarquía, pero el formulario no aparece en la lista de aplicaciones para elegir. Busqué en StackOverflow y encontré I should be able to use VisualTreeHelper class, pero no entiendo cómo usarlo.

¿Alguna idea?

Respuesta

6

FindName funciona en el scope de nombres XAML del control que realiza la llamada. En su caso, dado que el control se crea completamente dentro del código, ese namescope XAML está vacío, y es por eso que FindName falla. Ver this page:

Cualquier adición al árbol de elementos después de la carga y procesamiento inicial debe llamar a la aplicación adecuada de RegisterName para la clase que define la NameScope XAML. De lo contrario, el objeto agregado no puede referenciarse por nombre a través de métodos como FindName. Simplemente establecer una propiedad Name (o x: Name Attribute) no registra ese nombre en ningún namescope XAML.

La manera más fácil de solucionar su problema es almacenar una referencia a su etiqueta StatusDisplay en la clase como miembro privado. O bien, si desea aprender a usar la clase VisualTreeHelper, hay un fragmento de código at the bottom of this page que recorre el árbol visual para encontrar el elemento coincidente.

(Editado: Por supuesto, es menos trabajo para llamar RegisterName de utilizar el VisualTreeHelper, si no desea almacenar una referencia a la etiqueta.)

lo recomiendo leer el primer eslabón de en su totalidad si planea usar WPF/Silverlight en cualquier profundidad. Información útil para tener.

+0

Elegí, para este programa, para ir con el miembro privado. Gracias por la explicación, leeré la página completa tan pronto como pueda. –

2

usted tiene que crear una nueva NameScope para su ventana:

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

A continuación, se registra el nombre de la etiqueta con la ventana:

RegisterName(statusDisplay.Name, statusDisplay); 

Así que esto parece ser todo lo que necesita hacer para hacer que FindName() funcione.

Cuestiones relacionadas