Reputation: 16695
I have a strange problem where a XAML control is not visible in the code behind. Here is a sample of the XAML:
<ListView Name="lvtest" Grid.Row="2" Grid.ColumnSpan="2" Margin="0,20,0,0"
ItemsSource="{Binding Content}" >
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<WebView Name="contentView" Style="{StaticResource BodyTextStyle}" />
<TextBlock Name="testtxt" Text="{Binding}" Style="{StaticResource BodyTextStyle}" Foreground="GreenYellow"/>
In the code behind:
this.lvtest
is recognised, but:
this.contentView
and this.testtxt
are both not.
I've also tried x:Name
.
I'm clearly missing something obvious here, I just can't see what.
EDIT:
To clarify, the textbox control was going to be used to display some formatted text based on the binding, but what I have discovered is that the text is HTML formatted (this suggests using a WebView control). As far as I can see I need to NavigateToString
to use the WebView control, and so can't bind it as such.
Upvotes: 3
Views: 6894
Reputation: 56536
What you're missing is that the elements defined in a DataTemplate may be on the page any number of times, which can even change while running. Which one should be linked to the contentView
field? There's no good way to answer that, so it simply doesn't create a contentView
field.
To put it another way, you're not defining that the page includes those elements, you're declaring a template from which .NET can create elements.
If you let us know how you're trying to use it, we might be able to suggest another way.
Edit: Something like this might work for you:
<WebView Loaded="contentView_Loaded" Style="{StaticResource BodyTextStyle}" />
Then in the code:
void contentView_Loaded(object sender, EventArgs e)
{
var contentView = (WebView)sender;
var dataContext = (YourDataType)contentView.DataContext;
// do something
}
Upvotes: 8
Reputation: 23113
They are hidden because they are inside a template control.
From http://social.msdn.microsoft.com/Forums/en/wpf/thread/29ecc8ee-26ee-4331-8f97-35ff9d3e6886
<ListView Name="listview">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" >
<TextBlock Name="textYear" Text="{Binding Year}" />
<TextBlock Text=" " />
<TextBlock Name="textDayOffWeek" Text="{Binding DayOfWeek}" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<s:DateTime >1/2/2007</s:DateTime>
<s:DateTime >1/3/2008</s:DateTime>
<s:DateTime >1/5/2007</s:DateTime>
<s:DateTime >1/6/2006</s:DateTime>
</ListView>
<Button Width="180" Height="30" Content="Find TextBlock in DataTemplate" Click="FindElement" />
</StackPanel>
In the code behind:
private void FindElement(object sender, RoutedEventArgs e)
{
// get the current selected item
ListViewItem item = listview.ItemContainerGenerator.ContainerFromIndex(listview.SelectedIndex) as ListViewItem;
TextBlock textYear = null;
if (item != null)
{
//get the item's template parent
ContentPresenter templateParent = GetFrameworkElementByName<ContentPresenter>(item);
//get the DataTemplate that TextBlock in.
DataTemplate dataTemplate = listview.ItemTemplate;
if (dataTemplate != null && templateParent != null)
{
textYear = dataTemplate.FindName("textYear", templateParent) as TextBlock;
}
if (textYear != null)
{
MessageBox.Show(String.Format("Current item's Year is:{0}", textYear.Text));
}
}
}
private static T GetFrameworkElementByName<T>(FrameworkElement referenceElement) where T : FrameworkElement
{
FrameworkElement child = null;
for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceElement); i++)
{
child = VisualTreeHelper.GetChild(referenceElement, i) as FrameworkElement;
System.Diagnostics.Debug.WriteLine(child);
if (child != null && child.GetType() == typeof(T))
{ break; }
else if (child != null)
{
child = GetFrameworkElementByName<T>(child);
if (child != null && child.GetType() == typeof(T))
{
break;
}
}
}
return child as T;
}
Upvotes: 3