获取 DataTemplate 的子项会抛出 "catastrophic failure"(WP 8.1)

Getting children of DataTemplate throws "catastrophic failure" (WP 8.1)

我正在尝试创建一个 Windows Phone 8.1 应用程序。每当我尝试获取 DataTemplate 的子项(这是必需的,因为它们嵌入在 ListView 中)时,我都会得到一个详细说明 a

的异常

Catastrophic failure (Exception from HRESULT: 0x8000FFFF (E_UNEXPECTED))

我在这里做了一个非常简单的复现:

在 Visual Studio 中,创建一个新的 Windows Phone 空白应用程序模板。在 MainPage.xaml 的 OnNavigatedTo 事件处理程序中,添加 一行代码 :

var count = VisualTreeHelper.GetChildrenCount(new DataTemplate());

当你调试这个应用程序时,它会直接说 "An unhandled System.Exception has occured in user code."

我已经检查了 MSDN 以确保此方法不会抛出任何异常。

它失败了,因为 DataTemplate 不是可视对象并且没有可视子对象。 (显然 VisualTreeHelper.GetChildrenCount 实际上并没有检查您是否正在传递视觉效果,这就是为什么您看到灾难性故障而不是正常异常的原因)。

通常您不需要查看 ListView 的可视化树。通常,您可以将 ItemsSource 设置为自定义 class 的集合,其中包含您需要的所有属性。

如果您仍然需要 ListViewItem 中的实际视觉效果 - 这是极端情况下的最后手段 - 那么您可以创建一个自定义附加 属性(-ies) 并将其附加到相关视觉效果) 在你的数据模板中。当您附加的 属性 更改事件触发时,事件发送者将是相关的视觉对象,而该发送者的 DataContext 将是该列表项的数据值。

例如,如果您在 ListView 中有一个按钮,并希望单击该按钮来触发一个动作,那么您可以这样做:

    <ListView.ItemTemplate>
        <DataTemplate>
            <Button MyClickHelper.ClickHandler="{Binding}"/>
        </DataTemplate>
    </ListView.ItemTemplate>

然后,在你的 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
    }
}

这称为附加行为 - 修改按钮行为的附加 属性。这是一个有用的模式,它在代码的不同部分之间保持良好的界限,并允许每个按钮具有规定的行为,而无需某些必须直接管理所有不同按钮的主人 class。