Reputation: 636
I'm trying to change the selected state of items in a bound listbox based on if an object is used in the class that the item is bound to, I just can't seem to find a way of doing it and it has to remain dynamic because the object may change and thus used in different instances of the class:
<Popup x:Name="ContextMenuPopup" Height="250" Width="300" Margin="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Canvas Name="popupholder" Background="DarkSeaGreen" Height="250" Width="300" HorizontalAlignment="Center">
<StackPanel Orientation="Vertical">
<TextBlock Name="popupTitle" Text="Select Investments" Margin="20,0,0,0" FontFamily="Courier New" FontSize="22" HorizontalAlignment="Center" Foreground="Black" />
<ListBox x:Name="investPicker" SelectionChanged="ListBox_SelectionChanged" LayoutUpdated="investPicker_LayoutUpdated" HorizontalContentAlignment="Center" VerticalContentAlignment="Center" Margin="10,20,0,0" SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Name}" Width="100"/>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button Name="executeSelection" Content="Ok" Click="executeSelection_Click" Margin="40,5,0,0" VerticalAlignment="Bottom"/>
</StackPanel>
</Canvas>
</Popup>
Thwe code behind is:
private void ApplicationBarIconButton_Click_1(object sender, EventArgs e)
{
this.investPicker.ItemsSource = storedInvestments;
foreach (Investment investment in investPicker.Items)
{
foreach (CardDataSet card in investment.attachedCards)
if (card.ID == activeCard.ID)
VisualStateManager.GoToState((ListBoxItem) investPicker.Items[investment.ID -1], "Selected", true);
}
ContextMenuPopup.IsOpen = true;
}
Now obviously the code doesn't work as its an invalid cast from my class to a ListBoxItem, anyone know how I could do this?
Upvotes: 0
Views: 456
Reputation: 32067
Looks like you'll only have a single selected item, so how about this:
investPicker.SelectedItem = storedInvestments
.FirstOrDefault(i => i.attachedCards.Any(c => c.Id == activeCard.ID));
Or if you've got more than one:
var matchingItems = storedInvestments
.Where(i => i.attachedCards.Any(c => c.Id == activeCard.ID));
foreach (var i in matchingItems)
investPicker.SelectedItems.Add(i);
[edit]
OP didn't know what the arrow operator =>
means, so let's clarify a bit. It's called a lambda expression, which you can for the purposes of this discussion think of as a small, inline method.
This expression:
i.attachedCards.Any(c => c.Id == activeCard.ID);
can be read as "does i.attachedCards contain any Card c for which c.Id is equal to activeCard.ID".
The bit that says c => c.Id == activeCard.ID
denotes a method that could also be written as:
static bool IsActiveCard(Card c) { return c.Id == activeCard.ID; }
and in fact, if you were to write it so, you could change the expression to:
i.attachedCards.Any(IsActiveCard);
The rest of the expression is a call to the IEnumerable<T>
extension method Any
which evaluates the method for every element in the attachedCards
sequence until it either finds an element where the method returns true, or the sequence ends. It then returns true if it found an element or false if it didn't.
This bit then:
storedInvestments
.FirstOrDefault(i => i.attachedCards.Any(c => c.Id == activeCard.ID));
can be read as "give me the first matching Investment i in storedInvestments for which i.attachedCards contains a Card c ..." and so on.
It looks for the first element in the storedInvestments
sequence where the inner expression returns true. If it doesn't find anything, it returns the default value for the type (which is likely to be null
, unless storedInvestments
is a struct
).
I won't go on about the technical details, but if you're really interested in how all this works, Jon Skeet has written a great series of articles on how it's actually implemented. Highly recommended. :)
Upvotes: 1