I have a listbox containing and image and a button. By default the button is hidden. I want to make the button visible whenever I hover over an item in the listbox.
The XAML I am using is below. Thanks
<Window.Resources>
<Style TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border BorderBrush="Black" BorderThickness="1" Margin="6">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=FullPath}" Height="150" Width="150"/>
<Button x:Name="sideButton" Width="20" Visibility="Hidden"/>
</StackPanel>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
Ok, try this in your button declaration:
<Button x:Name="sideButton" Width="20">
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Visibility" Value="Hidden" />
<Style.Triggers>
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor,AncestorType={x:Type ListBoxItem}},Path=IsMouseOver}" Value="True">
<Setter Property="Visibility" Value="Visible" />
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
So I'm using a style with a trigger to look back up the visual tree until I find a ListBoxItem
, and when its IsMouseOver
property flips over to True
I set the button
's visibility to Visible
.
See if it's close to what you want.
This Style
does what you need. On mouse over, the button becomes only visible when the pointer is over the ListBoxItem
. The special trick is to bind to the TemplatedParent
for reaching IsMouseOver
and use TargetName
on the Setter
to only affect the Button
.
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Border BorderBrush="Black"
BorderThickness="1"
Margin="6">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=FullPath}"
Height="150"
Width="150" />
<Button x:Name="sideButton"
Width="20"
Visibility="Hidden" />
</StackPanel>
</Border>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsMouseOver,RelativeSource={RelativeSource TemplatedParent}}"
Value="True">
<Setter Property="Visibility"
TargetName="sideButton"
Value="Visible" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
@David is showing the right way,
But I have one suggestion to your XAML architecture. If you don't have any DataBinding on the Button it is better to put that in to the ListBoxItem style than the DataTemplate as bellow.
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Border BorderBrush="Black"
BorderThickness="1"
Margin="6">
<StackPanel Orientation="Horizontal">
<Image Source="{Binding Path=FullPath}"
Height="150"
Width="150" />
</StackPanel>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid Background="Transparent">
<Button x:Name="sideButton" Width="20" HorizontalAlignment="Right" Visibility="Hidden" />
<ContentPresenter/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Visibility"
TargetName="sideButton"
Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
One solution to find what item was clicked is to add the following Event setter
XAML
C#
void ListBoxItem_MouseEnter(object sender, MouseEventArgs e)
{
_memberVar = (sender as ListBoxItem).Content;
}
Just wondering, if we use the technique above, how do we determine what item the button was clicked on?
To answer Brian's question, in the button click handler you can walk up the visual tree to find the item that contains the button:
DependencyObject dep = (DependencyObject)e.OriginalSource;
while ((dep != null) && !(dep is ListBoxItem))
{
dep = VisualTreeHelper.GetParent(dep);
}
if (dep != null)
{
// TODO: do stuff with the item here.
}