FindName返回null

我正在为学校写一个简单的tic tac toe游戏。 作业是用C ++编写的,但老师允许我使用C#和WPF作为挑战。 我已经完成了所有游戏逻辑并且表单大部分都已完成,但我遇到了一堵墙。 我目前正在使用一个Label来表明它是谁,我想在玩家进行有效移动时更改它。 根据Applications = Code + Markup ,我应该能够使用Window类的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上搜索并发现我应该可以使用VisualTreeHelper类 ,但我不明白如何使用它。

有任何想法吗?

FindName在调用控件的XAML名称范围内运行。 在您的情况下,由于控件完全在代码中创建,因此XAML名称范围为空 – 这就是FindName失败的原因。 看这个页面 :

初始加载和处理后对元素树的任何添加都必须为定义XAML名称范围的类调用RegisterName的相应实现。 否则,添加的对象不能通过FindName等方法按名称引用。 仅设置Name属性(或x:Name Attribute)不会将该名称注册到任何XAML名称范围中。

解决问题的最简单方法是将类中的StatusDisplay标签的引用存储为私有成员。 或者,如果您想学习如何使用VisualTreeHelper类,那么本页底部会有一个代码片段,用于遍历可视树以查找匹配元素。

(编辑:当然,如果您不想存储对标签的引用,则调用RegisterName比使用VisualTreeHelper要少。)

如果您计划在任何深度使用WPF / Silverlight,我建议您完整阅读第一个链接。 有用的信息。

您必须为您的窗口创建一个新的NameScope:

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

然后在窗口中注册标​​签名称:

 RegisterName(statusDisplay.Name, statusDisplay); 

所以这似乎是使FindName()工作所需要做的全部工作。