【问题标题】:WPF: Display a bool value as "Yes" / "No"WPF:将布尔值显示为“是”/“否”
【发布时间】:2009-05-08 21:11:48
【问题描述】:

我有一个布尔值,需要在 TextBlock 中显示为“是”或“否”。我正在尝试使用 StringFormat 执行此操作,但我的 StringFormat 被忽略并且 TextBlock 显示“True”或“False”。

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

我的语法有问题,还是不支持这种类型的 StringFormat?

我知道我可以使用 ValueConverter 来完成此操作,但 StringFormat 解决方案似乎更优雅(如果有效的话)。

【问题讨论】:

    标签: wpf data-binding xaml formatting


    【解决方案1】:

    你也可以使用this great value converter

    然后你在 XAML 中声明如下:

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

    你可以这样使用它:

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

    【讨论】:

    • XAML 真的很喜欢它的价值转换器。最简单的任务:300 行值转换器。
    • 请使用有效链接更新答案
    • @Brandon 是的,但你只需要编写这 300 行代码,然后它们就可以重复使用。除非您需要稍微不同的结果。
    【解决方案2】:

    您使用 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
        }
    
    }
    

    【讨论】:

    • 你是对的,这不是 bool 值的有效格式字符串(它对数值有效)。我正在测试这样的格式字符串:string.Format("{0:Yes;;No}", 1),它返回“Yes”,但 string.Format("{0:Yes;;No}", true ) 返回“真”。谢谢
    • 您能否建议,在使用此转换器进行绑定时如何使用 ElementName?
    • @conqenator,只需添加ElementName=xxx,就像普通绑定一样
    • 这个怎么用? Text="{extensions:SwitchBinding {Binding Path=IsOnline}, ONLINE, OFFLINE}" -- 这告诉我它不能将绑定转换为字符串?
    • @user230910,使用属性名即可:Text="{extensions:SwitchBinding IsOnline, ONLINE, OFFLINE}"
    【解决方案3】:

    不带转换器

                <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>
    

    【讨论】:

    • 我喜欢这个解决方案。我知道转换器是一种常见的解决方案;但是,在大型应用程序中,似乎最好以自己的方式解决问题(通过DataTrigger,因为您最终可能会得到大量的单例转换器)。
    • 你不应该同时触发真假,这是不必要的,而且会导致问题。在这种情况下,您应该为该属性设置一个默认设置器和一个 DataTrigger
    【解决方案4】:

    还有另一个非常棒的选择。检查这一点:Alex141 CalcBinding

    在我的 DataGrid 中,我只有:

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

    要使用它,您只需通过 Nuget 添加 CalcBinding,而不是在 UserControl/Windows 声明中添加

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

    【讨论】:

      【解决方案5】:

      这是一个使用ConverterConverterParameter 的解决方案,它允许您为不同的Bindings 轻松定义不同的strings

      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="." />
      

      【讨论】:

        【解决方案6】:

        这是另一种具有“硬编码”是/否值的简化转换器

        [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" />
        

        【讨论】:

          【解决方案7】:

          以下内容在 datagridtextcolumn 中对我有用:我向我的类添加了另一个属性,该属性根据 MyBool 的值返回一个字符串。 请注意,在我的情况下,数据网格绑定到 MyClass 对象的 CollectionViewSource。

          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}">
          

          【讨论】:

            【解决方案8】:

            更详细的版本基于Cedre's answer

            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>
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-07-17
              • 1970-01-01
              • 2021-03-24
              • 1970-01-01
              • 1970-01-01
              • 2013-12-18
              相关资源
              最近更新 更多