1

The end goal to be able to set a specific ItemContainerStyle on the first and last element in my list box;

The converters thus far are:

public class IsFirstItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool result = false;
        result = ((IList<object>)parameter).First() == value;

        return result;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
public class IsLastItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool result = false;
        result = ((IList<object>)parameter).Last() == value;

        return result;
    }

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

And implementation:

<DataTrigger Value="True" Binding="{Binding Converter={StaticResource IsFirstItemConverter},ConverterParameter=Items,  ElementName=SubItems}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="First"/>
                    <ContentPresenter/>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</DataTrigger>

And the error is:

InvalidCastException: Unable to cast object of type 'System.String' to type 'System.Collections.Generic.IList`1[System.Object]'.

Im sure I screwed up in multiple spots, just not experienced enough with XAML and bindings to narrow down where.

Taterhead
  • 5,763
  • 4
  • 31
  • 40
Wobbles
  • 3,033
  • 1
  • 25
  • 51
  • 1
    [Click](http://stackoverflow.com/a/12131197/1997232). – Sinatr Mar 04 '16 at 15:15
  • Take a look at [this](http://stackoverflow.com/questions/13613053/how-can-i-know-if-a-listboxitem-is-the-last-item-inside-a-wpfs-listbox) – Ponas Justas Mar 04 '16 at 15:17
  • @Sinatr Ohh my, that works even cleaner than the way I was trying to do it, please post as an answer (even though its just a reference to elsewhere) so I can accept it. This is definitely getting added to my library of common converters. – Wobbles Mar 04 '16 at 15:26
  • @Wobbles, I rather expect from you to post an answer ;). After you adapt it to work for you case: to find first and last item. If you are not going to, then feel free to simply delete question. – Sinatr Mar 04 '16 at 15:30
  • Anybody know why these data triggers wouldn't be firing when the collection changes? – Wobbles Mar 05 '16 at 12:58

1 Answers1

1

The following adapted from the questions comments work perfectly:

public class IsLastItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        DependencyObject item = (DependencyObject)value;
        ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);

        return ic.ItemContainerGenerator.IndexFromContainer(item) == ic.Items.Count - 1;
    }

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

public class IsFirstItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        DependencyObject item = (DependencyObject)value;
        ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);

        return ic.ItemContainerGenerator.IndexFromContainer(item) == 0;
    }

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

public class IsOnlyItemConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        DependencyObject item = (DependencyObject)value;
        ItemsControl ic = ItemsControl.ItemsControlFromItemContainer(item);

        return (ic.ItemContainerGenerator.IndexFromContainer(item) == 0 && ic.ItemContainerGenerator.Items.Count == 1);
    }

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

Implementation:

<DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource IsLastItemConverter}}" Value="True">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="└"/>
                    <ContentPresenter/>
                </StackPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</DataTrigger>

The magic seems to be that ItemsControlFromItemContainer makes it so I do not have to pass both the item and its collection instance to the converter but just the item and the converter can infer the parent collection.

Wobbles
  • 3,033
  • 1
  • 25
  • 51