WPF: отображать значение bool как "Да" / "Нет"

У меня есть значение bool, которое мне нужно отобразить как "Да" или "Нет" в TextBlock. Я пытаюсь сделать это с помощью StringFormat, но мой StringFormat игнорируется, и TextBlock отображает "True" или "False".

<TextBlock Text="{Binding Path=MyBoolValue, StringFormat='{}{0:Yes;;No}'}" />

Что-то не так с моим синтаксисом, или этот тип StringFormat не поддерживается?

Я знаю, что могу использовать ValueConverter для достижения этой цели, но решение StringFormat кажется более элегантным (если оно работает).

8 ответов

Решение

Ваше решение с StringFormat не может работать, потому что это недопустимая строка формата.

Я написал расширение разметки, которое будет делать то, что вы хотите. Вы можете использовать это так:

<TextBlock Text="{my:SwitchBinding MyBoolValue, Yes, No}" />

Вот код для расширения разметки:

public class SwitchBindingExtension : Binding
{
    public SwitchBindingExtension()
    {
        Initialize();
    }

    public SwitchBindingExtension(string path)
        : base(path)
    {
        Initialize();
    }

    public SwitchBindingExtension(string path, object valueIfTrue, object valueIfFalse)
        : base(path)
    {
        Initialize();
        this.ValueIfTrue = valueIfTrue;
        this.ValueIfFalse = valueIfFalse;
    }

    private void Initialize()
    {
        this.ValueIfTrue = Binding.DoNothing;
        this.ValueIfFalse = Binding.DoNothing;
        this.Converter = new SwitchConverter(this);
    }

    [ConstructorArgument("valueIfTrue")]
    public object ValueIfTrue { get; set; }

    [ConstructorArgument("valueIfFalse")]
    public object ValueIfFalse { get; set; }

    private class SwitchConverter : IValueConverter
    {
        public SwitchConverter(SwitchBindingExtension switchExtension)
        {
            _switch = switchExtension;
        }

        private SwitchBindingExtension _switch;

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            try
            {
                bool b = System.Convert.ToBoolean(value);
                return b ? _switch.ValueIfTrue : _switch.ValueIfFalse;
            }
            catch
            {
                return DependencyProperty.UnsetValue;
            }
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return Binding.DoNothing;
        }

        #endregion
    }

}

Вы также можете использовать этот отличный преобразователь стоимости

Затем вы объявляете в XAML что-то вроде этого:

<local:BoolToStringConverter x:Key="BooleanToStringConverter" FalseValue="No" TrueValue="Yes" />

И вы можете использовать это так:

<TextBlock Text="{Binding Path=MyBoolValue, Converter={StaticResource BooleanToStringConverter}}" />

Без конвертера

            <TextBlock.Style>
                <Style TargetType="{x:Type TextBlock}">
                    <Setter Property="Text" Value="OFF" />
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding MyBoolValue}" Value="True">
                            <Setter Property="Text" Value="ON" />
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBlock.Style>

Есть и еще один действительно отличный вариант. Проверьте это: https://github.com/Alex141/CalcBinding.

В моей DataGrid у меня есть только:

<DataGridTextColumn Header="Mobile?" Binding="{conv:Binding (IsMobile?\'Yes\':\'No\')}" />

Чтобы использовать его, вам нужно только добавить CalcBinding через GitHub, чем в объявлении UserControl/Windows, вы добавляете

<Windows XXXXX xmlns:conv="clr-namespace:CalcBinding;assembly=CalcBinding"/>

Это решение с использованием Converter и ConverterParameter что позволяет легко определять разные strings для разных Bindings:

public class BoolToStringConverter : IValueConverter
{
    public char Separator { get; set; } = ';';

    public object Convert(object value, Type targetType, object parameter,
                          CultureInfo culture)
    {
        var strings = ((string)parameter).Split(Separator);
        var trueString = strings[0];
        var falseString = strings[1];

        var boolValue = (bool)value;
        if (boolValue == true)
        {
            return trueString;
        }
        else
        {
            return falseString;
        }
    }

    public object ConvertBack(object value, Type targetType, object parameter,
                              CultureInfo culture)
    {
        var strings = ((string)parameter).Split(Separator);
        var trueString = strings[0];
        var falseString = strings[1];

        var stringValue = (string)value;
        if (stringValue == trueString)
        {
            return true;
        }
        else
        {
            return false;
        }
    }
}

Определите конвертер так:

<local:BoolToStringConverter x:Key="BoolToStringConverter" />

И используйте это так:

<TextBlock Text="{Binding MyBoolValue, Converter={StaticResource BoolToStringConverter},
                                       ConverterParameter='Yes;No'}" />

Если вам нужен другой разделитель, чем ; (например .), определите конвертер следующим образом:

<local:BoolToStringConverter x:Key="BoolToStringConverter" Separator="." />

Это еще один альтернативный упрощенный преобразователь с "жестко закодированными" значениями Да / Нет.

[ValueConversion(typeof (bool), typeof (bool))]
public class YesNoBoolConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var boolValue = value is bool && (bool) value;

        return boolValue ? "Yes" : "No";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value != null && value.ToString() == "Yes";
    }
}

Использование XAML

<DataGridTextColumn Header="Is Listed?" Binding="{Binding Path=IsListed, Mode=TwoWay, Converter={StaticResource YesNoBoolConverter}}" Width="110" IsReadOnly="True" TextElement.FontSize="12" />

Следующее сработало для меня в datagridtextcolumn: я добавил в свой класс еще одно свойство, которое возвращало строку в зависимости от значения MyBool. Обратите внимание, что в моем случае сетка данных была привязана к CollectionViewSource объектов MyClass.

C#:

public class MyClass        
{     
    public bool MyBool {get; set;}   

    public string BoolString    
    {    
        get { return MyBool == true ? "Yes" : "No"; }    
    }    
}           

XAML:

<DataGridTextColumn Header="Status" Binding="{Binding BoolString}">

Более подробная версия, основанная на ответе Седре :

User.cs

      namespace DataTriggerDemo.Model
{
    public class User : INotifyPropertyChanged
    {
        private bool isConnected = false;
        public bool IsConnected
        {
            get => isConnected;
            set
            {
                isConnected = value;
                OnPropertyChanged(nameof(IsConnected));
            }
            public event PropertyChangedEventHandler PropertyChanged;
            public void OnPropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    }
}

MainWindow.xaml.cs

      public partial class MainWindow : Window
{
    private User user;
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    user = FindResource("user") as User;
}

private void ButtonStart_Click(object sender, RoutedEventArgs e)
{
    user.IsConnected = !user.IsConnected;
    return;
}

MainWindow.xaml

      <Window x:Class="DataTriggerDemo.MainWindow"
        
        xmlns:model="clr-namespace:DataTriggerDemo.Model"
        Title="Data Trigger Demo" Height="100" Width="100" Loaded="Window_Loaded">

    <Window.Resources>
        <model:User x:Key="user"/>
    </Window.Resources>
    <!-- ... -->
    <TextBlock>
        <TextBlock.Style>
            <Style TargetType="{x:Type TextBlock}">
                <Setter Property="Text" Value="Disconnected" />
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Source={StaticResource ResourceKey=user}, Path=IsConnected}" Value="True">
                        <Setter Property="Text" Value="Connected" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </TextBlock.Style>
    </TextBlock>
    <!-- ... -->
</Window>
Другие вопросы по тегам