I would like to change the image of an WPF Button
on ListView
empty, but I don't now which is the property I must set from the trigger.
<Style x:Key="DisableOnEmptyLvStyle" TargetType="{x:Type Button}">
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=myListView, Path=Items.Count}" Value="0">
<Setter Property="IsEnabled" Value="False"/>
<!-- which button property I must set here? -->
</DataTrigger>
</Style.Triggers>
</Style>
<Button Style="{StaticResource DisableOnEmptyLvStyle}">
<Image Source="{StaticResource myImage}"/>
</Button>
Once ListView
has items, then the image must change to the normal one.
Any ideas how to do this?
CodePudding user response:
You should never set the Content
directly using a Style
, simply because the Style
is instantiated once and potentially reused across multiple controls. The issue is that the value that you assign in the Setter
for Content
is also instantiated once and shared, but a control can only have a single parent in WPF.
What can go wrong? If you set or change the Content
in a style and reference it for e.g. multiple Button
s you will see that only the last button shows the image. The first button gets its image set as Content
, then the next button sets the image as Content
and effectively removes the content of the first button.
There are two options that you can consider.
Create the images as resources and force each reference in XAML to get a new instance of the image by setting the
x:Shared
attribute toFalse
.When set to
false
, modifies WPF resource-retrieval behavior so that requests for the attributed resource create a new instance for each request instead of sharing the same instance for all requests.<Window.Resources> <!-- ...your image sources for "myImage" and "myImage". --> <Image x:Key="myImageConrol" x:Shared="False" Source="{StaticResource myImage}"/> <Image x:Key="myOtherImageConrol" x:Shared="False" Source="{StaticResource myImage}"/> <Style x:Key="DisableOnEmptyLvStyle" TargetType="{x:Type Button}"> <Setter Property="Content" Value="{StaticResource myImageConrol}"/> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=myListView, Path=Items.Count}" Value="0"> <Setter Property="IsEnabled" Value="False" /> <Setter Property="Content" Value="{StaticResource myOtherImageConrol}"> </Setter> </DataTrigger> </Style.Triggers> </Style> </Window.Resources>
<Button Style="{StaticResource DisableOnEmptyLvStyle}"/>
Create data templates and swap them out. This works because - as the name says - they are templates and its controls will be instantiated for each control they are applied to.
<Style x:Key="DisableOnEmptyLvStyle" TargetType="{x:Type Button}"> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <Image Source="{StaticResource myImage}"/> </DataTemplate> </Setter.Value> </Setter> <Style.Triggers> <DataTrigger Binding="{Binding ElementName=myListView, Path=Items.Count}" Value="0"> <Setter Property="IsEnabled" Value="False" /> <Setter Property="ContentTemplate"> <Setter.Value> <DataTemplate> <Image Source="{StaticResource myOtherImage}"/> </DataTemplate> </Setter.Value> </Setter> </DataTrigger> </Style.Triggers> </Style>
<Button Style="{StaticResource DisableOnEmptyLvStyle}"/>
CodePudding user response:
Please try the following:
<Style x:Key="DisableOnEmptyLvStyle" TargetType="{x:Type Button}">
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource myImageAtLeastOne}"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding ElementName=myListView, Path=Items.Count}" Value="0">
<Setter Property="IsEnabled" Value="False" />
<Setter Property="Content">
<Setter.Value>
<Image Source="{StaticResource myImageEmpty}"/>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
<Button Style="{StaticResource DisableOnEmptyLvStyle}" />