Home > database >  How to change Button Image when ListView is empty through a trigger
How to change Button Image when ListView is empty through a trigger

Time:03-24

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 Buttons 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.

  1. 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 to False.

    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}"/>
    
  2. 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}" />
  • Related