wpfdatatriggerstackpanel

wpf visibility based on a condition


I want to show a StackPanel based on a particular condition. In this example I've used the BorderThickness property:

<ContentControl x:Name="gridDati" VirtualizingPanel.VirtualizationMode="Recycling" VirtualizingPanel.ScrollUnit="Item" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
    <ContentControl.Style>
        <Style TargetType="ContentControl">
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Items}" Value="{x:Null}">
                    <Setter Property="BorderThickness" Value="0" />
                </DataTrigger>
                <DataTrigger Binding="{Binding Path=Items.Count}" Value="0">
                    <Setter Property="BorderThickness" Value="12" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ContentControl.Style>
</ContentControl>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="pnlLoading" Visibility="Visible">
    <Label Content="">
        <Label.Style>
            <Style>
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=BorderThickness, ElementName=gridDati, UpdateSourceTrigger=PropertyChanged}" Value="0">
                        <Setter Property="TextBlock.Text" Value="" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=BorderThickness, ElementName=gridDati, UpdateSourceTrigger=PropertyChanged}" Value="12">
                        <Setter Property="TextBlock.Text" Value="STAND BY" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Label.Style>
    </Label>
</StackPanel>

Basically when in the code behind I apply a template on gridDati, while the item counter is still zero, the border is set correctly to 12. After that it turns to zero (item binded) and this behevior is what I want.

So, I also would like to show a StackPanel at the same condition, so I used a DataTrigger but seems that is not fired at all. How can I "link" these two condition? so show a stackpanel when I have items in the datagrid?


Solution

  • This is the proper way to declare the Label so you get the desired result.

    <Label>
        <Label.Style>
            <Style TargetType="Label">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=Items.Count}" Value="0">
                        <Setter Property="Content" Value="STAND BY"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Label.Style>
    </Label>
    

    But there are a few points I need to explain to make sure you understand what I changed and why. I'm going to go through the XAML from the inside out.

    First, I changed the Setter to use the right property name. You're using a Label, and your old Setter had Property="TextBlock.Text". TextBlock.Text is not a valid property name for a Label (no such property exists), so that wasn't going to work. The property you want is called Content.

    Moving up one level to the DataTrigger. Instead of binding to gridDati that is binding to Items, I just bound directly to Items. You could do it the other way, but in my opinion it would be unusual and it might cause unforeseen bugs.

    Next, you'll notice I removed the first DataTrigger. WPF dependency properties can be set in a number of different ways, and there is an order of precedence for which value will be taken over others. The default value (lowest precedence) for a Label's content is for it to be empty. When the DataTrigger applies the Setter, it overrides that value (it has higher precedence). When the DataTrigger condition is no longer fulfilled (Items.Count != 0), WPF stops applying the Setter and the value reverts back to the default, because there is no longer any value of higher precedence overriding it. So you don't need to add a second DataTrigger resetting to default, wit ill do that automatically.

    Moving up further you'll see I changed the opening Style tag to <Style TargetType="Label">. It's common practice to set the TargetType of a Style. Doing this also gives you IntelliSense options for Setters in that Style, which might have helpped you catch the mistake you made by trying to use TextBlock.Text as a property name.

    Finally, I removed Content="" from the opening Label tag. Setting the value of a property directly on an element in XAML has a very high precedence, which overrides all Styles and DataTriggers. As long as this was there, nothing you did in any Style would change anything for the Label's Content.