Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
236 views
in Technique[技术] by (71.8m points)

c# - FindName returning null

I'm writing a simple tic tac toe game for school. The assignment is in C++, but the teacher has given me permission to use C# and WPF as a challenge. I've gotten all the game logic finished and the form mostly complete, but I've run into a wall. I'm currently using a Label to indicate who's turn it is, and I want to change it when a player makes a valid move. According to Applications = Code + Markup, I should be able to use the FindName method of the Window class. However, it keeps returning null. Here's the code:

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";
    }
}

What's going on here? I'm using the same name in both places, but FindName can't find it. I've tried using Snoop to see the hierarchy, but the form doesn't show up in the list of applications to choose from. I searched on StackOverflow and found I should be able to use VisualTreeHelper class, but I don't understand how to use it.

Any ideas?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

FindName operates on the XAML namescope of the calling control. In your case, since the control is created entirely within code, that XAML namescope is empty -- and that's why FindName fails. See this page:

Any additions to the element tree after initial loading and processing must call the appropriate implementation of RegisterName for the class that defines the XAML namescope. Otherwise, the added object cannot be referenced by name through methods such as FindName. Merely setting a Name property (or x:Name Attribute) does not register that name into any XAML namescope.

The easiest way to fix your problem is to store a reference to your StatusDisplay label in the class as a private member. Or, if you want to learn how to use the VisualTreeHelper class, there's a code snippet at the bottom of this page that walks the visual tree to find the matching element.

(Edited: Of course, it's less work to call RegisterName than to use the VisualTreeHelper, if you don't want to store a reference to the label.)

I'd recommend reading the first link in its entirety if you plan on using WPF/Silverlight in any depth. Useful information to have.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...