0
votes

I've been scouring the internet for a week looking for an answer to my question, but nobody else seems to be hitting this issue.

I am migrating an app from Windows Phone 8 Silverlight to Windows Phone 8.1 WinRT, and am having an issue with a custom control I made. In the Silverlight app, I created a custom LongListSelector that I predefined a ItemTemplate for with custom binding and logic. I reuse this LongListSelector in a few different places in the app.

I am trying to do the same thing in my WinRT app, but with ListView. The issue is that when I try to include my custom extended ListView in any XAML page, I get an E_UNKNOWN_ERROR XamlParseException with the Line and Position number set to the end of the opening tag of my ListView.

Here is what my custom ListView's XAML looks like:

<ListView
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyAppNamespace"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sys="using;System;assembly=mscorlib"
    x:Class="MyAppNamespace.CustomListView"
    x:Name="This"
    mc:Ignorable="d"
    d:DesignHeight="300"
    d:DesignWidth="400"
    ItemsSource="{Binding}">

    <ListView.ItemTemplate>
        <DataTemplate>

            .... my data template is here ...

        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

And my code-behind is this:

namespace MyAppNamespace
{
    public partial class CustomListView: ListView
    {
        public CustomListView()
        {
            this.InitializeComponent();
        }

        ... event handlers and custom logic here ...
    }
}

And here's how I reference it in another XAML page

<Page
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:MyAppNamespace"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    x:Class="MyAppNamespace.SamplePage"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <Grid>


        <local:CustomListView DataContext="{Binding Items}"/>
    </Grid>

</Page>

The error shows up in Blend and in the design view of the xaml file in Visual Studio. When I run the app and navigate to the page where I am using this control, the error appears on the LoadComponent function call within the generated InitializeComponent.

The weird thing is that if I switch the root element to UserControl and put the ListView inside it (and update the base class in the code-behind), then everything works fine, but I'd rather just directly extend the ListView then wrap it in a UserControl.

2
Is there an InnerException?SLaks
Have you tried isolating the issue? Making it a minimal control with minimal template and then extending property by property, method by method etc.?Igor Ralic
Yes, I have tried it with noting inside my custom ListView, and I still see the same. There are three levels of exception. The outer-most is Cannot create an instance of "CustomListView". The innerException for that is TargetInvocationException: Exception has been thrown by the target of an invocation. The inner error for that is XamlParseException: The text associated with this error code could not be found. E_UNKNOWN_ERROR [Line: 13 Position: 29] dslane

2 Answers

1
votes

Finally figured it out!!

I needed to override the PrepareContainerForItemOverride and then set the Loaded event for the ListViewItem passed in as the first parameter. Then, in the event handler, apply the callbacks as needed by traversing the element tree.

PrepareContainerForItemOverride will be called every time a row of the ExtendedListView is populated with a different element from the ItemsSource, but the Loaded callback will only be called once per row unless the row is unloaded (you can also add a callback handler for this if needed.

Below is some sample code to help out anyone else who has this issue!!

Here's the relevant contents of ExtendedListView.cs:

public sealed class ExtendedListView : ListView
{
    public ExtendedListView()
    {
        this.DefaultStyleKey = typeof(ExtendedListView);
    }

    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        base.PrepareContainerForItemOverride(element, item);
        ListViewItem lvi = element as ListViewItem;
        lvi.Loaded += lvi_Loaded;
    }

    void lvi_Loaded(object sender, RoutedEventArgs e)
    {
        ListViewItem lvi = sender as ListViewItem;
        ApplyCallbacksToElement(lvi.ContentTemplateRoot);
    }

    private void ApplyCallbacksToElement(DependencyObject element)
    {
        if (null != element)
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(element);
            for (int i = 0; i < childrenCount; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(element, i);
                // Code for adding element callbacks goes here
                //
                // For example:
                // if (IsButtonAndMatchesCondition(child))
                // {
                //     (child as Button).Click += button_Click;
                // }
                //
                ApplyCallbacksToElement(child);
            }
        }
    }
}

And here's the relevant content of the Generic.xaml file generated in the Themes folder created after making a new TemplatedControl:

<Style TargetType="local:ExtendedListView">
    <Setter Property="IsTabStop"
            Value="False" />
    <Setter Property="TabNavigation"
            Value="Once" />
    <Setter Property="IsSwipeEnabled"
            Value="True" />
    <Setter Property="ScrollViewer.HorizontalScrollBarVisibility"
            Value="Disabled" />
    <Setter Property="ScrollViewer.VerticalScrollBarVisibility"
            Value="Auto" />
    <Setter Property="ScrollViewer.HorizontalScrollMode"
            Value="Disabled" />
    <Setter Property="ScrollViewer.IsHorizontalRailEnabled"
            Value="False" />
    <Setter Property="ScrollViewer.VerticalScrollMode"
            Value="Enabled" />
    <Setter Property="ScrollViewer.IsVerticalRailEnabled"
            Value="False" />
    <Setter Property="ScrollViewer.ZoomMode"
            Value="Disabled" />
    <Setter Property="ScrollViewer.IsDeferredScrollingEnabled"
            Value="False" />
    <Setter Property="ScrollViewer.BringIntoViewOnFocusChange"
            Value="True" />
    <Setter Property="ItemContainerTransitions">
        <Setter.Value>
            <TransitionCollection>
                <AddDeleteThemeTransition />
                <ContentThemeTransition />
                <ReorderThemeTransition />
                <EntranceThemeTransition IsStaggeringEnabled="False" />
            </TransitionCollection>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemsPanel">
        <Setter.Value>
            <ItemsPanelTemplate>
                <ItemsStackPanel Orientation="Vertical" />
            </ItemsPanelTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="ItemTemplate">
        <Setter.Value>
            <DataTemplate>
                <!-- Put your custom DataTemplate here -->
            </DataTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="local:ExtendedListView">
                <Border BorderBrush="{TemplateBinding BorderBrush}"
                        Background="{TemplateBinding Background}"
                        BorderThickness="{TemplateBinding BorderThickness}">
                    <ScrollViewer x:Name="ScrollViewer"
                                  TabNavigation="{TemplateBinding TabNavigation}"
                                  HorizontalScrollMode="{TemplateBinding ScrollViewer.HorizontalScrollMode}"
                                  HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
                                  IsHorizontalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsHorizontalScrollChainingEnabled}"
                                  VerticalScrollMode="{TemplateBinding ScrollViewer.VerticalScrollMode}"
                                  VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}"
                                  IsVerticalScrollChainingEnabled="{TemplateBinding ScrollViewer.IsVerticalScrollChainingEnabled}"
                                  IsHorizontalRailEnabled="{TemplateBinding ScrollViewer.IsHorizontalRailEnabled}"
                                  IsVerticalRailEnabled="{TemplateBinding ScrollViewer.IsVerticalRailEnabled}"
                                  ZoomMode="{TemplateBinding ScrollViewer.ZoomMode}"
                                  IsDeferredScrollingEnabled="{TemplateBinding ScrollViewer.IsDeferredScrollingEnabled}"
                                  BringIntoViewOnFocusChange="{TemplateBinding ScrollViewer.BringIntoViewOnFocusChange}"
                                  AutomationProperties.AccessibilityView="Raw">
                        <ItemsPresenter Header="{TemplateBinding Header}"
                                        HeaderTemplate="{TemplateBinding HeaderTemplate}"
                                        HeaderTransitions="{TemplateBinding HeaderTransitions}"
                                        Footer="{TemplateBinding Footer}"
                                        FooterTemplate="{TemplateBinding FooterTemplate}"
                                        FooterTransitions="{TemplateBinding FooterTransitions}"
                                        Padding="{TemplateBinding Padding}" />
                    </ScrollViewer>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>
0
votes

You can only extend controls that inherit from UserControl the way you are trying (Like Page for example).

What you have to do is just create a class that inherits from ListView and modify default style for it.

<Style TargetType="my:CustomListView">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="..">

...