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

时间:2019-07-28 01:29:38

标签: c# visual-studio uwp windows-10-universal textblock

我在ContentControl的XAML表单上创建了一个文本块。当我尝试对其进行编程时,C#无法识别该名称,并且对此也无能为力。

我尝试将文本块添加到内容控件之外的表单中,但这仍然不能解决问题。

这是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>

然后是相应的工作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;
}

我希望能够更改文本块的文本。而是出现错误“名称lblCalorieGoal.Text在当前上下文中不存在。”

1 个答案:

答案 0 :(得分:1)

此处的关键实现是模板可能是XAML的可重用部分,因此实际上其中的任何内容都嵌入了其中,而不是“可公开访问的”,因为在视图上可能存在同一模板的多个实例。

话虽如此,您仍然可以通过使用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;
}

请注意,此操作仅在加载控件后有效(例如,在Page.Loaded事件处理程序-

中)
private void MainPage_Loaded(object sender, RoutedEventArgs e)
{
    var block = FindChildByName(ContentRoot, "lblCalorieGoal") as TextBlock;
}

但是,这都不是解决您问题的理想解决方案。相反,您应该完全放弃使用ContentControl,并将控件直接放在页面上的模板中(这将使它们可以直接从后面的代码中直接访问),或/和/或使用数据绑定来绑定数据直接转到适当的控件。在这种情况下,我将创建一个类来保存数据,例如:

public class NutritionInfo
{
    public string CalorieGoal { get; set; }
}

现在而不是ContentControl.ControlTemplate(它将替换整个控件的模板),您将替换ContentTemplate(实际上是ControlTemplate实际上显示的东西):

<ContentControl x:Name="ContentRoot">
   <ContentControl.ContentTemplate>
        <DataTemplate x:DataType="local:NutritionInfo">
                ... your template
        </DataTemplate>
   </ContentControl.ContentTemplate>
</ContentControl>

请注意,我们使用x:DataType来指定绑定到的类型,以便我们可以使用x:Bind语法。最后,我们更新模板本身:

<TextBlock x:Name="lblCalorieGoal" Text="{x:Bind CalorieGoal}" ... />

我们使用x:BindTextBlock的文本绑定到CalorieGoal属性。我们差不多完成了,现在只需将Content的{​​{1}}属性设置为ContentControl的实例(例如,通过数据绑定或直接):

NutritionInfo

总体而言,我建议进一步阅读XAML中数据绑定的工作原理,因为这将帮助您显着简化代码,避免直接通过ContentRoot.Content = new NutritionInfo() { CalorieGoal = "1243" }; 访问控件,并使UI与代码脱钩。有关更多信息,请参见documentation