Windows Phone 8.1 Toggling the visibility of a TextBlock in a DataTemplate

The problem I’m having is that I can’t access the TextBlock from the C# code.

Yes, since the TextBlock is defined inside a DataTemplate, the TextBlock won’t be available until the DataTemplate has been applied. Thus, the x:Name attribute won’t automatically generate a variable reference in the InitializeComponent method in your *.g.i.cs file. (Read up on XAML Namescopes for more information).

If you want to access it from your code-behind, there are two ways:

The first way is the simplest: you can get a reference to the TextBlock in the sender argument of the Loaded event handler for that TextBlock.

<TextBlock Loaded="NoArticlesTextBlock_Loaded" />

Then in your code-behind:

private TextBlock NoArticlesTextBlock;

private void NoArticlesTextBlock_Loaded(object sender, RoutedEventArgs e)
{
    NoArticlesTextBlock = (TextBlock)sender;
}

The second way is to traverse the visual tree manually to locate the element with the required name. This is more suitable for dynamic layouts, or when you have a lot of controls you want to reference that doing the previous way would be too messy. You can achieve it like this:

<Page Loaded="Page_Loaded" ... />

Then in your code-behind:

static DependencyObject FindChildByName(DependencyObject from, string name)
{
    int count = VisualTreeHelper.GetChildrenCount(from);

    for (int i = 0; i < count; i++)
    {
        var child = VisualTreeHelper.GetChild(from, i);
        if (child is FrameworkElement && ((FrameworkElement)child).Name == name)
            return child;

        var result = FindChildByName(child, name);
        if (result != null)
            return result;
    }

    return null;
}

private TextBlock NoArticlesTextBlock;

private void Page_Loaded(object sender, RoutedEventArgs e)
{
    // Note: No need to start searching from the root (this), we can just start
    // from the relevant HubSection or whatever. Make sure your TextBlock has
    // x:Name="NoArticlesTextBlock" attribute in the XAML.
    NoArticlesTextBlock = (TextBlock)FindChildByName(this, "NoArticlesTextBlock");
}

Jerry Nixon has a good page on his blog about this.

Leave a Comment