简体   繁体   English

背后的代码无法识别标签名称

[英]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:BindTextBlock的文本x:BindCalorieGoal属性。 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): 我们差不多完成了,现在只需将ContentControlContent属性设置为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.

相关问题 在代码隐藏中添加后,RadGrid ItemCommand不会触发 - RadGrid ItemCommand Doesn't Fire When Added In Code-Behind 标签引用在代码后面的适当位置 - Appropriate location of label reference in code-behind updatepanel.update()似乎没有从隐藏代码中触发 - updatepanel.update() doesn't appear to fire from code-behind 在 WPF 中的代码隐藏中更改时,int 类型的属性不会反映在 UI 中? - Property of type int doesn't reflect in UI when changed in code-behind in WPF? 如何在代码隐藏中创建未指定路径的绑定? - How can I create a binding in code-behind that doesn't specify a Path? OnClientClick事件不会从代码隐藏中注册javascript警报 - OnClientClick event doesn't register javascript alert from code-behind 从代码隐藏访问GridView标签字段 - Accessing GridView Label field from Code-Behind CallMethodAction不执行Windows Phone 8.1中的代码隐藏方法 - CallMethodAction doesn't execute code-behind methods in Windows Phone 8.1 双击按钮不会打开其代码隐藏 - Double-clicking a button doesn't open its code-behind 即使重新生成了designer.cs文件,TextBox也不会出现在代码隐藏中 - TextBox doesn't appear in code-behind even though I regenerated the designer.cs file
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM