简体   繁体   中英

Conditional text binding XAML

I have 3 properties that I'm trying to bind to a Textblock in XAML. One is a conditional and the other two are the strings that I want to display depending on that conditional.

<TextBlock Text="{Binding TrueText}" Style="{StaticResource styleSimpleText}" Visibility="{Binding ShowTrueText, Converter={StaticResource boolToVisibilityConverter}}"/>
<TextBlock Text="{Binding FalseText}" Style="{StaticResource styleSimpleText}" Visibility="{Binding ShowTrueText, Converter={StaticResource invertedBoolToVisibilityConverter}}"/>

This works, but now the textblocks have to have different names. Can I turn this into one TextBlock with the conditional inside of it?

You could achieve that with a Style and a DataTrigger:

<TextBlock>
    <TextBlock.Style>
        <Style TargetType="TextBlock">
            <Setter Property="Text" Value="{Binding FalseText}"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding ShowTrueText}" Value="True">
                    <Setter Property="Text" Value="{Binding TrueText}"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </TextBlock.Style>
</TextBlock>

An alternative would be to use a MultiBinding with a multi-value converter:

<TextBlock>
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource TextConverter}">
            <Binding Path="TrueText"/>
            <Binding Path="FalseText"/>
            <Binding Path="ShowTrueText"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>

The converter would look like this:

public class TextConverter : IMultiValueConverter
{
    public object Convert(
        object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        var trueText = (string)values[0];
        var falseText = (string)values[1];
        var showTrueText = (bool)values[2];
        return showTrueText ? trueText : falseText;
    }

    public object[] ConvertBack(
        object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

Yes, you can, just wrap them in a TextBlock as follows:

<TextBlock x:name="myTextBlock" Style="{StaticResource styleSimpleText}">
    <TextBlock Text="{Binding TrueText}" Visibility="{Binding ShowTrueText, Converter={StaticResource boolToVisibilityConverter}}"/>
    <TextBlock Text="{Binding FalseText}" Visibility="{Binding ShowTrueText, Converter={StaticResource invertedBoolToVisibilityConverter}}"/>
</TextBlock>

However, I think the best answer is the one provided by Clemens (using a DataTrigger).

In my opinion, the best solution to this problem would be a new string property in your view model which returns either TrueText or FalseText depending on the conditional. With such a property, you can just use a plain binding.

public string TheNewProperty
{
    get
    {
        return ShowTrueText ? TrueText : FalseText;
    }
}
<TextBlock Text="{Binding TheNewProperty}" Style="{StaticResource styleSimpleText}"/>

The way we do this type of thing for MVVM is to create a property in your viewmodel for this. This allows for you to have unit testing for your condition on the viewmodel.

The property in your viewmodel will be the string value that the TextBlock is bound to. The viewmodel at some point will determine the value of that string based on the conditional logic that you need.

You could set it up in your viewmodel and let it determine which text to show.

private static readonly string TRUETEXT = "This is the text to show when true";
    private static readonly string FALSETEXT = "This is the text to show when false";

    private bool _myBooleanProperty;
    public bool MyBooleanProperty
    {
        get { return _myBooleanProperty; }
        set
        {
            if (_myBooleanProperty != value)
            {
                _myBooleanProperty = value;
                OnPropertyChanged("MyBooleanProperty");
                OnPropertyChanged("ResultText");
            }
        }
    }

    public string ResultText
    {
        get
        {
            return MyBooleanProperty ? TRUETEXT : FALSETEXT;
        }
    }

Then you bind to it with just a single textblock. No visibility converter needed.
If there is a state where no text should show, you could work that in as well.

<TextBlock Text="{Binding ResultText}" Style="{StaticResource styleSimpleText}" />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM