Reputation: 34499
I am attempting to create a Windows Phone 8.1 application. Whenever I attempt to get the children of a DataTemplate (which is necessary because they are embedded in a ListView), I get an Exception that details a
Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))
I have made a very simple repro here:
In Visual Studio, create a new Windows Phone Blank App template. In the MainPage.xaml, in the OnNavigatedTo event handler, add a single line of code:
var count = VisualTreeHelper.GetChildrenCount(new DataTemplate());
When you debug this app, it says straightaway that "An unhandled System.Exception has occured in user code."
I have checked MSDN to make sure that this method should not throw any exceptions.
Upvotes: 1
Views: 630
Reputation: 2204
It's failing because DataTemplate
isn't a visual object and doesn't have visual children. (Apparently VisualTreeHelper.GetChildrenCount
doesn't actually check that you are passing in a visual, and that's why you see a catastrophic failure instead of a normal exception).
Normally you don't need to look at the visual tree for a ListView. Usually you can set your ItemsSource to a collection of a custom class that contains properties for everything you need.
If you still need the actual visuals in a ListViewItem - and this is a corner-case last resort - then you create a custom attached property(-ies) and attach it to the relevant visual(s) in your DataTemplate. When your attached property change event fires, the event sender will be the relevant visual and the DataContext of that sender will be the data value of that list item.
If for instance you have a button in a ListView
and want the button click to trigger an action, then you would do something like this:
<ListView.ItemTemplate>
<DataTemplate>
<Button MyClickHelper.ClickHandler="{Binding}"/>
</DataTemplate>
</ListView.ItemTemplate>
Then, in your class MyClickHelper
:
private static void OnClickHandlerChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var button = (Button)d;
var data = (MyDataType)e.NewValue;
button.Click += (btn, args) =>
{
// do action here based on data above
}
}
This is called an attached behavior - an attached property that modifies the behavior of the button. It's a useful pattern that keeps good boundaries between different parts of the code and allows each button to have a behavior prescribed without some master class that has to manage all the different buttons directly.
Upvotes: 2