Hi,
I have a ListBox in a file called Downloads.XAML. The items bound to that ListBox come from a bound list in my ViewModel. I have states that are defined in the ListBoxItem style in a different XAML control which need to be fired depending on a property set on the bound item. The problem I have is that I cannot get the ListBoxItem from the ListBox, as the .SelectedItem refers to the actual bound object rather than the ListBox. I have tried using the ListBox.ItemContainerGenerator but this only returns a ListItem about 80% of the time, the other 20% of the time this returns null and therefore the VisualState does not get set on the relevant ListBoxItem.
I've also tried setting the states through datatriggers in the XAML but again this doesnt work 100% of the time. Does anyone know how I can easily get the ListBoxItem from the bound object in order to fire off the VisualState on it that I require?
The items that are bound to the list in the ListBox are added from a different page - the downloads page is not visible at this time and I am thinking that this is why the ListBoxItems arent being found or why the states arent being fired?
Here is the XAML of the ListBoxItem control template within the style:
<Style x:Key="PrimaryDownloadsListBoxItemStyle" TargetType="ListBoxItem">
<Setter Property="Padding" Value="3"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="VerticalContentAlignment" Value="Top"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="TabNavigation" Value="Local"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem" >
<Grid Margin="0" Height="71">
<Grid.RowDefinitions>
<RowDefinition Height="5"/>
<RowDefinition Height="5"/>
<RowDefinition Height="52"/>
<RowDefinition Height="5"/>
<RowDefinition Height="5"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="90"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="184"/>
<ColumnDefinition Width="116"/>
<ColumnDefinition Width="220"/>
<ColumnDefinition Width="67"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
<VisualStateGroup x:Name="SelectionStates">
<VisualState x:Name="Unselected"/>
<VisualState x:Name="Selected">
<Storyboard>
<ColorAnimation Duration="0" To="#FF191919" Storyboard.TargetProperty="(Shape.Fill).(SolidColorBrush.Color)" Storyboard.TargetName="fillColor2" d:IsOptimized="True"/>
</Storyboard>
</VisualState>
<VisualState x:Name="SelectedUnfocused"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FocusStates">
<VisualState x:Name="Focused"/>
<VisualState x:Name="Unfocused"/>
</VisualStateGroup>
<VisualStateGroup x:Name="LayoutStates">
<VisualState x:Name="AfterLoaded"/>
<VisualState x:Name="BeforeLoaded"/>
<VisualState x:Name="BeforeUnloaded"/>
</VisualStateGroup>
<VisualStateGroup x:Name="DownloadStates">
<VisualState x:Name="DownloadInProgress">
...
Here is the code I'm using in the code behind to attempt to set the state:
private void SetDownloadState(object[] itemDetails)
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
var item = itemDetails;
if (item != null)
{
string state = (string)item[0];
VideoItem vi = (VideoItem)item[1];
if (DownloadsListBox.ItemContainerGenerator != null)
{
DownloadsListBox.ScrollIntoView(DownloadsListBox.Items[0]);
foreach (var videoitem in
DownloadsListBox.Items.Where(videoitem => videoitem == vi))
{
DownloadsListBox.ScrollIntoView(videoitem);
}
var listBoxItem = DownloadsListBox.ItemContainerGenerator.ContainerFromItem(vi) as ListBoxItem;
//show the status state on this item.
if (listBoxItem != null)
{
if (state.ToUpper() == "DOWNLOADING")
{
bool success = VisualStateManager.GoToState(listBoxItem, "DownloadInProgress", true);
if (!success)
{
Debug.WriteLine("Error changing state in DownloadsView to Downloading!");
}
}
else if (state.ToUpper() == "COMPLETED")
{
bool success = VisualStateManager.GoToState(listBoxItem, "DownloadComplete",
true);
if (!success)
{
Debug.WriteLine("Error changing state in DownloadsView to completed!");
}
}
}
else
{
Debug.WriteLine("listBoxItem is null");
}
}
}
});
}
I did try adding the triggers into the ContentTemplate within the style but it didnt work 100% of the time:
<i:Interaction.Triggers>
<ei:DataTrigger Binding="{Binding DownloadState}" Value="Downloading">
<ei:GoToStateAction StateName="Focused"/>
<ei:GoToStateAction StateName="DownloadInProgress"/>
</ei:DataTrigger>
<ei:DataTrigger Binding="{Binding DownloadState}" Value="DownloadComplete">
<ei:GoToStateAction StateName="Focused"/>
<ei:GoToStateAction StateName="DownloadComplete"/>
</ei:DataTrigger>
</i:Interaction.Triggers>