1
votes

For some reason, my LongListSelector is passing its inherited DataContext into my ItemTemplate converter causing the list items to display their default .ToString() value instead of my template.

I initially had the ItemTemplate defined as a Button control with a Template bound to a property of the items bound to the LongListSelector and that used an IValueConverter to grab the proper ControlTemplate:

ParentViewModel.cs

...
List<ChildViewModel> ChildViewModels { get; set; }
...

ChildViewModel.cs

...
MyEnumType MyEnumType { get; set; }
...

MainPage.xaml

<phone:LongListSelector x:Name="MyLongListSelector"
                        IsGroupingEnabled="False"
                        ItemsSource="{Binding ChildViewModels}">
    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <Button Template="{Binding MyEnumType, Converter={StaticResource MyConverter}}" DataContext="{Binding}"/>
        </DataTemplate>
    </phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>

This worked fine, but I'm pretty sure I don't need to define a Button as the data template since I should be able to capture anything I need based on the selection event of the LLS.

So, trying to do it right (in my eyes; this is my first real WP8 App), I changed all my Templates from ControlTemplates to DataTemplates and updated my MyConverter to return DataTemplate objects based on the ChildViewModelProperty bound to the ItemTemplate:

public class MyConverter : IValueConverter
{
    public object Converter(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        MyEnumType enumType = MyEnumType.DefaultType;
        Enum.TryParse<MyEnumType>(value.ToString(), out enumType);

        DataTemplate template = null;

        switch (enumType)
        {
            case MyEnumType.Type1:
                template = (DataTemplate)App.Current.Resources["MyEmumTypeTemplate1"];
                break;
            case MyEnumType.Type2:
                template = (DataTemplate)App.Current.Resources["MyEnumTypeTemplate2"];
                break;
            default:
                template = (DataTemplate)App.Current.Resources["MyEnumTypeTemplateDefault"];
                break;
        }

        return template;
    }

    ...
}

Then I updated my LongListSelector to bind the ItemTemplate directly to my ChildViewModelProperty of type MyEnumType with my MyConverter (declared in App.xaml as a static resource) converter as so:

<phone:LongListSelector x:Name="MyLongListSelector"
                        IsGroupingEnabled="False"
                        ItemsSource="{Binding ChildViewModels}"
                        ItemTemplate="{Binding MyEnumType, Converter={StaticResource MyConverter}}"
</phone:LongListSelector>

Now, when I view my app in the designer or in the emulator, my LongListSelector outputs a list with all of my elements presented as their .ToString() value (i.e. their fully qualified name).

What I've found is that ParentViewModel is being passed into MyConverter instead of each of the ChildViewModel.MyEnumType values. When I take out the specified Binding PropertyName (MyEnumProperty) and step through the debugger, value is of type ParentViewModel, the inherited DataContext of the LongListSelector. When I enter my desired Property name for the Binding, it simply fails the binding and doesn't even get into the Converter.

I saw a previous article that mentioned something about the LLS not handling a template change, but it had a comment (in 2011) that it's been fixed. I figured since it's 2013, it shouldn't be an issue anymore.

Am I missing something obvious, or do I need a go a little bit further? Or did I do it right in the first place with the Button?

Thanks for any help!

1

1 Answers

2
votes

The issue is that when your binding is evaluated in the context of the LongListSelector as a whole and at that time the data context is the ChildViewModels. It is not reevaluated when implementing the individual item.

The approach I'd take to address your problem would be to implement a custom DataTemplateSelector that can choose the datatemplate based on the enum value.

<phone:LongListSelector x:Name="MyLongListSelector"
                        IsGroupingEnabled="False"
                        ItemsSource="{Binding ChildViewModels}">
    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <MyDataTemplateSelector Content="{Binding}">
                <MyDataTemplateSelector.Type1>
                    <DataTemplate>
                        // ... your content here
                    </DataTemplate>
                </MyDataTemplateSelector.Type1>
                <MyDataTemplateSelector.Type2>
                    <DataTemplate>
                        // ... your content here
                    </DataTemplate>
                </MyDataTemplateSelector.Type2>
                <MyDataTemplateSelector.Default>
                    <DataTemplate>
                        // ... your content here
                    </DataTemplate>
                </MyDataTemplateSelector.Default>
            </MyDataTemplateSelector>
        </DataTemplate>
    </phone:LongListSelector.ItemTemplate>
</phone:LongListSelector>

There's an example of how to implement such a selector at http://www.geekchamp.com/articles/implementing-windows-phone-7-datatemplateselector-and-customdatatemplateselector