views:

249

answers:

2

I'm trying to figure out how to build a recursive binding in xaml. I know about HierarchialDataTemplate, but that's not what I want, because my data source is not a collection of items. Specifically, I'm building an exception browser, and am trying to figure out the best way of expressing the exception's InnerException field (which is of course another exception, hence recursion.)

This exception browser is part of a log viewer I'm building. Here is the XAML for the ListView so far:

<ListView x:Name="LogViewerOutput">
    <ListView.ItemTemplate>
        <DataTemplate DataType="Ushanka.Log.LogMessageEventArgs">
            <Expander Style="{StaticResource ExceptionTreeStyle}" Width="Auto">
                <Expander.Header>
                    <StackPanel Orientation="Horizontal">
                        <Image Stretch="Fill" Width="16" Height="16" Margin="5" 
                               Source="{Binding Path=Level, Converter={StaticResource LogLevelIconConverter}}" />
                        <TextBlock Text="{Binding Message}" />
                    </StackPanel>
                </Expander.Header>
                <Expander.Content>
                    <StackPanel Orientation="Vertical">
                        <TextBlock Text="{Binding Exception.Message}" />
                        <TextBlock Text="{Binding Exception.Source" />
                        <!-- Here I would like to somehow be able to recursively browse through the tree of InnerException -->
                    </StackPanel>
                </Expander.Content>
            </Expander>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Any ideas? Is this even possible?

+1  A: 

I would make a DataTemplate for an Exception and bind the InnerException to a ContentPresenter within it. The ContentPresenter will stop the chain when InnerExpception is null and you can format the exceptions however you want. Something like this:

<DataTemplate DataType="{x:Type Exception}">
    <StackPanel Orientation="Vertical">
        <TextBlock Text="{Binding Message}" />
        <TextBlock Text="{Binding Source"   />
        <ContentPresenter Content="{Binding InnerException}"    />
    </StackPanel>
</DataTemplate>
Bryan Anderson
Hmm. That's very close, but it seems to be simply rendering the InnerException as a string. I was hoping it could be recursively presented (like Visual Studio's exception browser) the same way as the top-level exception was.
Sean Edwards
You might need to assign keys to the DataTemplate then and assign it explicitly but you're probably going to end up with something like this.
Bryan Anderson
A: 

code to support getting the Exception type for the header:

class TypeConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value.GetType().ToString();
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

xaml:

<Window.Resources>

    <local:TypeConverter x:Key="TypeConverter"/>

    <DataTemplate DataType="{x:Type sys:Exception}">
        <Expander Header="{Binding Converter={StaticResource TypeConverter}}">
            <Expander.Content>
                <StackPanel Orientation="Vertical">
                    <TextBlock Text="{Binding Message}" />
                    <TextBlock Text="{Binding Source}"   />
                    <ContentPresenter Content="{Binding InnerException}"    />
                </StackPanel>
            </Expander.Content>               
        </Expander>
    </DataTemplate>   

</Window.Resources>
jesperll