views:

61

answers:

3

I have an Image inside an ItemTemplate for a ListBox. Is there a way in XAML to toggle its visibility based on the ListBox' SelectedItem?

In other words, I want the image to be visible only if the ListBoxItem is selected, but want to avoid code-behind for that.

Thanks.

+3  A: 

Edit the ListBox's ItemContainerStyle, and you will then have access to all the States for the ListBox items. These include the focussed and selected states. If you're doing this in Blend, it should be under "Edit Additional Templates" on the ListBox's context menu.

Then you should be able to change the layout for the Selected state, which should be what you need?

Ben Gracewood
+2  A: 

In the ItemContainerStyle for the listbox (in Blend, right-click on the ListBox in the Objects and Timeline and select Edit Additional Templates / Edit Generated Item Container (ItemContainerStyle) / Edit a Copy... Choose a name and location for the new style in the enusing dialog box.)

In the generated style, locate the ContentPresenter tag. Somewhere in that area (depending on your specific layout needs) you will want to drop your Image item. Set its visibility to bind to the IsSelected property of the templated parent...

<Image Source="{Binding Property2}" Visibility="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsSelected, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}}"/>

As you see in the markup above, you do have to use a value converter, so cannot get away from using SOME code...IsSelected is a Boolean value, Visibility is a member of the System.Windows.Visibility enumeration. To convert form one to the other, you'll need a ValueConverter that switches from one value domain to the other. The Boolean/Visibility converter is fairly common, and I've included a simple one below (I tend to have a "stock" one that I use that includes a parameter to set which value to map "true" to in order to make it more flexible, but omitted it for conciseness...)

public class BooleanToVisibilityConverter : IValueConverter
{
    public Object Convert(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture)
    {
        var booleanValue = (Boolean)value;
        return booleanValue ? Visibility.Visible : Visibility.Collapsed;
    }

    public Object ConvertBack(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture)
    {
        var visibilityValue = (Visibility) value;
        return visibilityValue == Visibility.Visible;
    }
}
avidgator
A: 

You could do this with the SelectionChanged event of the ListBox.

<Grid x:Name="LayoutRoot" Background="White">
    <ScrollViewer Height="500" Width="200">
        <ListBox x:Name="lstItems" SelectionChanged="lstItems_SelectionChanged">
            <ListBoxItem>
                <StackPanel Orientation="Horizontal">
                    <Image Source="Selected.png" Visibility="Collapsed"/>
                    <TextBlock Text="Item 1"/>
                </StackPanel>
            </ListBoxItem>
            <ListBoxItem>
                <StackPanel Orientation="Horizontal">
                    <Image Source="Selected.png" Visibility="Collapsed"/>
                    <TextBlock Text="Item 2"/>
                </StackPanel>
            </ListBoxItem>
        </ListBox>
    </ScrollViewer>
</Grid>

Handle the event:

private void lstItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    HideAllSelected();
    ListBoxItem item = lstItems.SelectedItem as ListBoxItem;
    StackPanel sp = item.Content as StackPanel;
    Image img = sp.Children[0] as Image;
    img.Visibility = Visibility.Visible;
}

private void HideAllSelected()
{
    foreach (ListBoxItem item in lstItems.Items)
    {
        StackPanel sp = item.Content as StackPanel;
        Image img = sp.Children[0] as Image;
        img.Visibility = Visibility.Collapsed;
    }
}
DaveB