Search code examples
gridviewuwpivalueconverter

UWP GridViewItem Binding Thicknesss to ItemIndex


I have an AdaptiveGridView control with an ItemTemplate that consists of a Grid containing a StackPanel with an Icon and a TextBlock. I want to give each Grid of the GridViewItem's ItemTemplate a different Thickness. Researching on how to do so, I found that binding the Thickness parameter to a IValueConverter is the best way to do it. The issue is that when I try it, I get an error stating:

System.InvalidCastException: 'Unable to cast object of type 'Test.Models.SampleOrder' to type 'Windows.UI.Xaml.Controls.GridViewItem'.'

This is what I'm trying:

Page.xaml

<Page.Resources>
    <converter:IndexToBorderThicknessConverter x:Name="indexconverter"/>
</Page.Resources>

<Grid x:Name="ContentArea" VerticalAlignment="Center">
    <controls:AdaptiveGridView
        ItemsSource="{x:Bind ViewModel.Source,Mode=OneWay}"
        <controls:AdaptiveGridView.ItemTemplate>
            <DataTemplate x:DataType="models:SampleOrder">
                <Grid
                    x:Name="itemThumbnail"  
                    BorderBrush="Gray"
                    BorderThickness="{Binding Converter={StaticResource indexconverter}}"
                    Padding="{StaticResource XSmallLeftTopRightBottomMargin}"
                    Background="White">
                    <StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
                        <FontIcon Glyph="{x:Bind Symbol}" />
                        <TextBlock
                            Margin="{StaticResource XXSmallTopMargin}"
                            HorizontalAlignment="Center"
                            Style="{ThemeResource BodyTextStyle}"
                            Text="{x:Bind Company}" />
                    </StackPanel>
                </Grid>
            </DataTemplate>
        </controls:AdaptiveGridView.ItemTemplate>
    </controls:AdaptiveGridView>
</Grid>

IndexToBorderThicknessConverter.cs

public class IndexToBorderThicknessConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
    {
        GridViewItem item = (GridViewItem)value;
        AdaptiveGridView gridView = ItemsControl.ItemsControlFromItemContainer(item) as AdaptiveGridView;
        int index = gridView.Items.IndexOf(item);
        Thickness thickness;
        if (index % 2 == 0)
        {
            thickness = new Thickness(1);
        }

        thickness = new Thickness(2);

        return thickness;
    }

    public object ConvertBack(object value, Type targetType, object parameter, string language)
    {
        throw new NotImplementedException();
    }
}

I can see that what it's being sent to the converter is the model of the SampleOrder and not the GridViewItem. So my question is: How to send the GridViewItem insted of the SampleOrder or how to get the GridViewItem from the SampleOrderSent?

Thanks a lot in advanced.

Cheers!!!


Solution

  • Instead of using a converter, you could handle the Loaded eventfor theGridelement in the template and use theVisualTreeHelperclass to find the parentGridViewItem` in the visual tree:

    private void itemThumbnail_Loaded(object sender, RoutedEventArgs e)
    {
        Grid grid = (Grid)sender;
        GridViewItem item = FindParent<GridViewItem>(grid);
        AdaptiveGridView gridView = ItemsControl.ItemsControlFromItemContainer(item) as AdaptiveGridView;
        int index = gridView.Items.IndexOf(grid.DataContext);
        grid.BorderThickness = (index % 2 == 0) ? new Thickness(1) : new Thickness(2);
    }
    
    private static T FindParent<T>(DependencyObject dependencyObject) where T : DependencyObject
    {
        DependencyObject parent = VisualTreeHelper.GetParent(dependencyObject);
        if (parent == null)
            return null;
    
        T parentT = parent as T;
        return parentT ?? FindParent<T>(parent);
    }
    

    XAML:

    <DataTemplate>
        <Grid
            x:Name="itemThumbnail"
            Loaded="itemThumbnail_Loaded"
            ...
    

    FindParent<AdaptiveGridView>(grid) also works if you don't need the GridViewItem.