Steztric
Steztric

Reputation: 2942

Xamarin.Forms binding with data trigger - value not updating

I want to show the elapsed time on a video. I have a label with a format specifier like this:

<Label Text="{Binding CurrentTime, StringFormat='{0:D3} seconds'}" />

This works, and I get a string like 053 seconds. I want to show the text Not playing when the video is not playing, which I specify like this:

<Label Text="{Binding CurrentTime, StringFormat='{0:D3} seconds'}">
    <Label.Triggers>
        <DataTrigger TargetType="Label" Binding="{Binding IsPlaying}" Value="False">
            <Setter Property="Text" Value="Not playing" />
        </DataTrigger>
    </Label.Triggers>
</Label>

This correctly displays Not playing when the video is not playing, but when it is, the label is stuck on 000 seconds forever. What is going wrong?

Edit

The view looks like this:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyNamespace.VideoPage"
             x:Name="ThePage"
             BindingContext="{x:Reference Name=ThePage}">
    <StackLayout>
        <Label VerticalOptions="Center" Text="{Binding CurrentTime, StringFormat='{0:D3} seconds'}" HorizontalOptions="StartAndExpand">
            <Label.Triggers>
                <DataTrigger TargetType="Label" Binding="{Binding IsPlaying}" Value="False">
                    <Setter Property="Text" Value="Not playing" />
                </DataTrigger>
            </Label.Triggers>
        </Label>
        <!-- More stuff -->
    </StackLayout>
</ContentPage>

The code-behind looks like this:

public partial class VideoPage : ContentPage
{
    private int currentTime;

    public int CurrentTime
    {
        get { return currentTime; }
        set
        {
            currentTime = value;
            OnPropertyChanged();
        }
    }

    private bool isPlaying;

    public bool IsPlaying
    {
        get { return isPlaying; }
        set
        {
            isPlaying = value;
            OnPropertyChanged();
        }
    }

    ...
}

Edit 2

With the help of Yuri's answer I fixed it with the following

<ContentPage.Resources>
    <ResourceDictionary>
        <Style TargetType="Label" x:Key="PlayingStyle">
            <Setter Property="Text" Value="Not playing" />
            <Style.Triggers>
                <DataTrigger TargetType="Label" Binding="{Binding IsPlaying}" Value="True">
                    <Setter Property="Text" Value="{Binding CurrentTime, StringFormat='{0:D3} seconds'}" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ResourceDictionary>
</ContentPage.Resources>
...
<Label Style="{StaticResource PlayingStyle}" />

Upvotes: 3

Views: 6799

Answers (1)

Yuri S
Yuri S

Reputation: 5370

Xaml seems to be confused by two different types of bindings to text - one from trigger and another "direct" This is how it works:

   <Label VerticalOptions="Center" HorizontalOptions="StartAndExpand">
        <Label.Triggers>
            <DataTrigger TargetType="Label" Binding="{Binding  IsPlaying}"  Value="True">
                <Setter Property="Text" Value="{Binding CurrentTime, StringFormat='{0:D3} seconds'}" />
            </DataTrigger>
            <DataTrigger TargetType="Label" Binding="{Binding  IsPlaying}"  Value="False">
                <Setter Property="Text" Value="Not playing" />
            </DataTrigger>
        </Label.Triggers>
    </Label>

Thinking about option to give a "default" value to the label and do it as a child without style

    <Label VerticalOptions="Center" HorizontalOptions="StartAndExpand" Text="Not playing">
        <Label.Triggers>
            <DataTrigger TargetType="Label" Binding="{Binding  IsPlaying}"  Value="True">
                <Setter Property="Text" Value="{Binding CurrentTime, StringFormat='{0:D3} seconds'}" />
            </DataTrigger>
        </Label.Triggers>
    </Label>

Upvotes: 4

Related Questions