WPF ListBox of Buttons: how to change selected item on click with XAML

16,068

Solution 1

Typically you style your DataTemplate to look and respond like a button if that is the effect you want e.g.

<ListBox.ItemTemplate>
    <DataTemplate>
        <Border BorderBrush="Black" BorderThickness="3" CornerRadius="10" Background="#FFD6D3D3" Margin="5">
            <Border x:Name="myBorder" BorderBrush="#FFD6D3D3" BorderThickness="4" CornerRadius="10" Padding="2">
                <Border.Background>
                    <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1" >
                        <GradientStop Color="#FFA5A5A5" Offset="1"/>
                        <GradientStop Color="White"/>
                    </LinearGradientBrush>
                </Border.Background>
                <StackPanel>
                    <Image Source="{Binding Icon}" MaxHeight="32" MaxWidth="32"/>
                    <TextBlock x:Name="TxtContent" Text="{Binding Label}"/>
                </StackPanel>
            </Border>
        </Border>
        <DataTemplate.Triggers>
            <DataTrigger Binding="{Binding Path=IsSelected, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBoxItem}}}" Value="True">
                <Setter TargetName="myBorder" Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
                            <GradientStop Color="#FFA5A5A5" Offset="1"/>
                            <GradientStop Color="White" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
                <Setter TargetName="TxtContent" Property="RenderTransform" >
                    <Setter.Value>
                        <TranslateTransform Y="2.0" />
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </DataTemplate.Triggers>
    </DataTemplate>
</ListBox.ItemTemplate>

You may also want to set the ItemContainerStyle to override the default styling for the SelectedItem:

<ListBox.ItemContainerStyle>
    <Style TargetType="{x:Type ListBoxItem}" >
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <ContentPresenter />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ListBox.ItemContainerStyle>

Solution 2

The button defined in your DataTemplate will be intercepting the click event before the ListBoxItem can handle it. Remove the ItemContainerStyle and the Button from your DataTemplate.

<ListBox.ItemTemplate> 
  <DataTemplate> 
    <StackPanel> 
     <Image Source="{Binding Icon}" MaxHeight="32" MaxWidth="32"/> 
     <TextBlock Text="{Binding Label}"/> 
    </StackPanel> 
   </DataTemplate> 
 </ListBox.ItemTemplate> 
Share:
16,068
Nitin Chhajer
Author by

Nitin Chhajer

.NET Software Engineer

Updated on June 27, 2022

Comments

  • Nitin Chhajer
    Nitin Chhajer almost 2 years

    I have a templated ListBox:

    <ListBox Grid.Row="0" Grid.Column="1" Background="Transparent" BorderThickness="0" x:Name="mainMenu"
        ItemsSource="{Binding Source={x:Static local:MenuConfig.MainMenu},  Mode=OneTime}"
       IsSynchronizedWithCurrentItem="True">
     <ListBox.ItemContainerStyle>
      <Style TargetType="ListBoxItem">
       <EventSetter Event="PreviewMouseUp" Handler="SelectCurrentItem"/>
      </Style>
     </ListBox.ItemContainerStyle>
     <ListBox.ItemsPanel>
      <ItemsPanelTemplate>
       <StackPanel Orientation="Horizontal"></StackPanel>
      </ItemsPanelTemplate>
     </ListBox.ItemsPanel>
      <ListBox.ItemTemplate>
      <DataTemplate>
       <Button>
        <StackPanel>
         <Image Source="{Binding Icon}" MaxHeight="32" MaxWidth="32"/>
         <TextBlock Text="{Binding Label}"/>
        </StackPanel>
       </Button>
      </DataTemplate>
     </ListBox.ItemTemplate>
    </ListBox>
    

    The selected item is updated manually with code behind:

    private void SelectCurrentItem(object sender, MouseButtonEventArgs e)
    {
        ListBoxItem item = (ListBoxItem) sender;
        item.IsSelected = true;
    }
    

    Is there a way to do this (update selected item on button click) with XAML only ?