Reputation: 3135
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.
Upvotes: 1
Views: 196
Reputation: 3135
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.
Upvotes: 1