简体   繁体   English

FindName返回null

[英]FindName returning null

I'm writing a simple tic tac toe game for school. 我正在为学校写一个简单的tic tac toe游戏。 The assignment is in C++, but the teacher has given me permission to use C# and WPF as a challenge. 作业是用C ++编写的,但老师允许我使用C#和WPF作为挑战。 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. 我目前正在使用一个Label来表明它是谁,我希望在玩家进行有效移动时更改它。 According to Applications = Code + Markup , I should be able to use the FindName method of the Window class. 根据Applications = Code + Markup ,我应该能够使用Window类的FindName方法。 However, it keeps returning null . 但是,它一直返回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. 我在两个地方使用相同的名称,但FindName找不到它。 I've tried using Snoop to see the hierarchy, but the form doesn't show up in the list of applications to choose from. 我尝试使用Snoop查看层次结构,但表单没有显示在可供选择的应用程序列表中。 I searched on StackOverflow and found I should be able to use VisualTreeHelper class , but I don't understand how to use it. 我在StackOverflow上搜索并发现我应该可以使用VisualTreeHelper类 ,但我不明白如何使用它。

Any ideas? 有任何想法吗?

FindName operates on the XAML namescope of the calling control. FindName在调用控件的XAML名称范围上运行。 In your case, since the control is created entirely within code, that XAML namescope is empty -- and that's why FindName fails. 在您的情况下,由于控件完全在代码中创建,因此XAML名称范围为空 - 这就是FindName失败的原因。 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. 初始加载和处理后对元素树的任何添加都必须为定义XAML名称范围的类调用RegisterName的相应实现。 Otherwise, the added object cannot be referenced by name through methods such as FindName. 否则,添加的对象不能通过FindName等方法按名称引用。 Merely setting a Name property (or x:Name Attribute) does not register that name into any XAML namescope. 仅设置Name属性(或x:Name Attribute)不会将该名称注册到任何XAML名称范围中。

The easiest way to fix your problem is to store a reference to your StatusDisplay label in the class as a private member. 解决问题的最简单方法是将类中的StatusDisplay标签的引用存储为私有成员。 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. 或者,如果您想学习如何使用VisualTreeHelper类,则可以在此页面底部找到一个代码片段用于遍历可视树以查找匹配元素。

(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.) (编辑:当然,如果你不想存储对标签的引用,那么调用RegisterName比使用VisualTreeHelper要少。)

I'd recommend reading the first link in its entirety if you plan on using WPF/Silverlight in any depth. 如果您计划在任何深度使用WPF / Silverlight,我建议您完整阅读第一个链接。 Useful information to have. 有用的信息。

You have to create a new NameScope for your window: 您必须为您的窗口创建一个新的NameScope:

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

Then you register name of your label with the window: 然后在窗口中注册标​​签名称:

RegisterName(statusDisplay.Name, statusDisplay);

So this seems to be all you need to do to make FindName() work. 所以这似乎是使FindName()工作所需要做的全部工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM