[英]Code-behind doesn't recognize the name of label
I created a textblock on a XAML form within a ContentControl. 我在ContentControl的XAML表单上创建了一个文本块。 When I try to program it, C# doesn't recognize the name and I can't do anything with it.
当我尝试对其进行编程时,C#无法识别该名称,并且我无法对其进行任何操作。
I tried adding a textblock to the form outside of the Content Control, but that still didn't fix the problem. 我尝试将文本块添加到内容控件之外的表单中,但这仍然无法解决问题。
Here is the XAML code: 这是XAML代码:
<ContentControl>
<ContentControl.Template>
<ControlTemplate>
<Grid VerticalAlignment="Bottom" Height="250" Margin="0,450,0,0">
<Rectangle Fill="Beige" Stroke="Black" StrokeThickness="3"
Width="639" Height="250" Margin="0,0,0,0"/>
<TextBlock Text="Goal:" FontSize="18" Margin="7,50,0,0"/>
<TextBlock Text="Eaten:" FontSize="18" Margin="7,120,0,0"/>
<TextBlock Text="Remaining:" FontSize="18" Margin="7,190,0,0"/>
<TextBlock Text="Calories:" FontSize="18" Margin="140,10,0,0"/>
<TextBlock Text="Fat(g):" FontSize="18" Margin="270,10,0,0"/>
<TextBlock Text="Carbs(g):" FontSize="18" Margin="380,10,0,0"/>
<TextBlock Text="Protein(g):" FontSize="18" Margin="520,10,0,0"/>
<TextBlock x:Name="lblCalorieGoal" Text="Peb"
TextAlignment="Center" FontSize="18" Margin="-290,50,0,0"/>
</Grid>
</ControlTemplate>
</ContentControl.Template>
<TextBlock Text="TextBlock" TextWrapping="Wrap"/>
</ContentControl>
And then here is the corresponding working C# code: 然后是相应的工作C#代码:
public LogFood()
{
this.InitializeComponent();
Windows.Storage.ApplicationDataContainer localSettings =
Windows.Storage.ApplicationData.Current.LocalSettings;
Windows.Storage.StorageFolder localFolder =
Windows.Storage.ApplicationData.Current.LocalFolder;
Windows.Storage.ApplicationDataCompositeValue composite =
(Windows.Storage.ApplicationDataCompositeValue)localSettings
.Values["nutritionSettings"];
int calorieMin = Convert.ToInt32(composite["calorieMin"]);
int calorieMax = Convert.ToInt32(composite["calorieMax"]);
int gramsFatMin = Convert.ToInt32(composite["gramsFatMin"]);
int gramsFatMax = Convert.ToInt32(composite["gramsFatMax"]);
int gramsCarbsMin = Convert.ToInt32(composite["gramsCarbsMin"]);
int gramsCarbsMax = Convert.ToInt32(composite["gramsCarbsMax"]);
int gramsProteinMin = Convert.ToInt32(composite["gramsProteinMin"]);
int gramsProteinMax = Convert.ToInt32(composite["gramsProteinMax"]);
lblCalorieGoal.Text = calorieMin;
}
I expect to be able to change the text of the textblock. 我希望能够更改文本块的文本。 Instead, I get the error, "The name lblCalorieGoal.Text does not exist in the current context."
而是收到错误消息“名称lblCalorieGoal.Text在当前上下文中不存在”。
The key realization here is that a template is potentially a reusable part of XAML, so anything inside is in fact embedded in it a not "publicly" accessible, as there could potentially be multiple instances of the same template materialized on the view. 此处的关键实现是模板可能是XAML的可重用部分,因此实际上其中嵌入的任何内容都不能“公开”访问,因为在视图上可能存在同一模板的多个实例。
That being said, you can still access the materialized children inside the template indirectly by searching for them within the template using VisualTreeHelper
- 话虽如此,您仍然可以通过使用
VisualTreeHelper
在模板中搜索物化子级来间接访问模板中的物化子级-
internal static FrameworkElement FindChildByName(DependencyObject startNode, string name)
{
int count = VisualTreeHelper.GetChildrenCount(startNode);
for (int i = 0; i < count; i++)
{
DependencyObject current = VisualTreeHelper.GetChild(startNode, i);
if (current is FrameworkElement frameworkElement)
{
if (frameworkElement.Name == name)
return frameworkElement;
}
var result = FindChildByName(current, name);
if ( result != null)
{
return result;
}
}
return null;
}
Note, that this works only after the control has loaded (for example in the Page.Loaded
event handler - 请注意,这仅在控件加载后才有效 (例如,在
Page.Loaded
事件处理程序中-
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
var block = FindChildByName(ContentRoot, "lblCalorieGoal") as TextBlock;
}
However, this all is not an ideal solution to your problem. 但是,这都不是解决您的问题的理想解决方案。 Instead, you should either ditch the use of
ContentControl
altogether and have the controls in the template directly on the page (which would make them directly accessible from the code-behind), or/and use data-binding to bind data directly to appropriate controls. 相反,您应该完全放弃使用
ContentControl
,并将控件直接放在页面上的模板中(这样可以直接从后面的代码直接访问它们),或者/和/或使用数据绑定将数据直接绑定到适当的控件。 In this case, I would create a class to hold the data, for example: 在这种情况下,我将创建一个类来保存数据,例如:
public class NutritionInfo
{
public string CalorieGoal { get; set; }
}
Now instead of ContentControl.ControlTemplate
(which replaces the template of the whole control), you will replace the ContentTemplate
instead (which is just the thing which `ControlTemplate in fact displays): 现在,代替
ContentControl.ControlTemplate
(它将替换整个控件的模板),而是将替换ContentTemplate
(这实际上是ControlTemplate实际上显示的东西):
<ContentControl x:Name="ContentRoot">
<ContentControl.ContentTemplate>
<DataTemplate x:DataType="local:NutritionInfo">
... your template
</DataTemplate>
</ContentControl.ContentTemplate>
</ContentControl>
Note we use x:DataType
to specify the type we bind to so that we can use x:Bind
syntax. 注意,我们使用
x:DataType
指定绑定到的类型,以便可以使用x:Bind
语法。 Finally, we update the template itself: 最后,我们更新模板本身:
<TextBlock x:Name="lblCalorieGoal" Text="{x:Bind CalorieGoal}" ... />
We use x:Bind
to bind the text of the TextBlock
to the CalorieGoal
property. 我们使用
x:Bind
将TextBlock
的文本x:Bind
到CalorieGoal
属性。 We are almost done, now just set the Content
property of the ContentControl
to an instance of NutritionInfo
(for example via data binding or directly): 我们差不多完成了,现在只需将
ContentControl
的Content
属性设置为NutritionInfo
的实例(例如,通过数据绑定或直接):
ContentRoot.Content = new NutritionInfo()
{
CalorieGoal = "1243"
};
Overall I recommend to read further about how data-binding works in XAML, as that will help you significantly simplify your code and avoid accessing controls directly via x:Name
, and decouple UI from your code. 总体而言,我建议进一步阅读有关XAML中数据绑定的工作原理,因为这将帮助您显着简化代码,并避免直接通过
x:Name
访问控件,并使UI与代码脱钩。 See documentation for more info. 请参阅文档以获取更多信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.