FindName возвращает ноль - PullRequest
       5

FindName возвращает ноль

5 голосов
/ 07 февраля 2010

Я пишу простую игру Tic Tac Toe для школы. Задание на C ++, но учитель дал мне разрешение использовать C # и WPF в качестве испытания. Я закончил всю игровую логику, и форма в основном заполнена, но я наткнулся на стену. В настоящее время я использую Label, чтобы указать, чей это ход, и я хочу изменить его, когда игрок делает правильный ход. Согласно Applications = Code + Markup , я должен иметь возможность использовать метод FindName класса Window. Тем не менее, он продолжает возвращаться 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 и обнаружил, что должен иметь возможность использовать класс VisualTreeHelper , но я не понимаю, как его использовать.

Есть идеи?

Ответы [ 2 ]

6 голосов
/ 07 февраля 2010

FindName работает на именной области XAML вызывающего элемента управления. В вашем случае, поскольку элемент управления создан полностью внутри кода, эта область имен XAML пуста, и именно поэтому FindName завершается ошибкой. См. эту страницу :

Любые дополнения к дереву элементов после начальной загрузки и обработки должны вызывать соответствующую реализацию RegisterName для класса, который определяет область имен XAML. В противном случае на добавленный объект нельзя ссылаться по имени через такие методы, как FindName. Простая установка свойства Name (или атрибута x: Name) не регистрирует это имя ни в какой области имен XAML.

Самый простой способ решить вашу проблему - сохранить ссылку на вашу метку StatusDisplay в классе как частный член. Или, если вы хотите узнать, как использовать класс VisualTreeHelper, в нижней части этой страницы есть фрагмент кода , который просматривает визуальное дерево, чтобы найти соответствующий элемент.

(Отредактировано: конечно, для вызова RegisterName меньше работы, чем для использования VisualTreeHelper, если вы не хотите сохранять ссылку на метку.)

Я бы рекомендовал прочитать первую ссылку полностью, если вы планируете использовать WPF / Silverlight на любой глубине. Полезную информацию иметь.

2 голосов
/ 07 февраля 2010

Вы должны создать новый NameScope для своего окна:

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

Затем вы зарегистрируете название вашего ярлыка в окне:

RegisterName(statusDisplay.Name, statusDisplay);

Так что это все, что вынужно сделать, чтобы FindName() заработало.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...