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>