Search code examples
windowsxamlwindows-runtimemvvmcross

MvvmCross Windows Phone 8.1 bind list selection to command, compilation failure


I've the following error:

Object of type Windows.UI.Xml.Controls.ListView cannot be converted to type System.Windows.DependencyObject

Due to the following code:

<ListView Grid.Row="1" ItemsSource="{Binding Cases}" IsItemClickEnabled="False" SelectionMode="Single">
    <ListView.ItemTemplate>
    <DataTemplate>
        <Grid>
                <TextBlock Text="{Binding Subject}" HorizontalAlignment="Left"></TextBlock>
            </Grid>
        </DataTemplate>
    </ListView.ItemTemplate>
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectionChanged">
            <i:InvokeCommandAction Command="{Binding ShowCaseCommand, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
</ListView>

I added EventTrigger to the namespace like so:

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"

I added Interaction to the project by adding a reference manually from C:\Program Files (x86)\Microsoft SDKs\Expression\Blend\.NETFramework\v4.5\Libraries\System.Windows.Interactivity.dll.

Of course removing the <i:Interaction.Triggers> block eliminates the error but I need to bind selection to a command, like I do in UIKit and Android.

So – what manner of deviltry is this?


Solution

  • The problem is that this code is not compatible with Windows Phone 8.1.

    The list view needs to be set up like so:

    <ListView Grid.Row="1" ItemsSource="{Binding Cases}"  IsItemClickEnabled="False" SelectionMode="Single">
        <ListView.ItemTemplate>
            <DataTemplate>
                <Grid>
                    <TextBlock Text="{Binding Subject}" HorizontalAlignment="Left"></TextBlock>
                </Grid>
            </DataTemplate>
        </ListView.ItemTemplate>
        <interactivity:Interaction.Behaviors>
            <core:EventTriggerBehavior EventName="SelectionChanged">
                <core:InvokeCommandAction Command="{Binding ShowCaseCommand, Mode=OneWay}" />
                </core:EventTriggerBehavior>
        </interactivity:Interaction.Behaviors>
    </ListView>
    

    One needs to add a reference to the Behaviors library, not Windows.Interaction.

    The code above requires the following attributes on the root node:

    xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
    xmlns:core="using:Microsoft.Xaml.Interactions.Core"
    

    This leads to another problem; while it will be bound to ShowCaseCommand, it will pass in instance of SelectionChangedEventArgs, rather than the selected list item.

    We solve this with CommandParameter.

    We add an attribute to the ListView, like so – <ListView Name='listView' ... – and this name allows us to refer to it later:

    <interactivity:Interaction.Behaviors>
        <core:EventTriggerBehavior EventName="SelectionChanged">
            <core:InvokeCommandAction Command="{Binding ShowCaseCommand, Mode=OneWay}" CommandParameter="{Binding ElementName=listView, Path=SelectedItem}" />
        </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
    

    By specifying the command parameter like this, we can pass the selected item as the parameter, making it compatible with the same sort of selection command one uses in iOS.