数据触发器没有触发正确的字符串值

本文关键字:字符串 触发器 数据 | 更新日期: 2023-09-27 18:06:55

思路是这样的。如果文本框为空,"DataTrigger"应该将轮廓(BorderBrush)设置为红色。如果文本框不是空的/有文本;那么dataTrigger应该将BorderBrush设置为蓝色。

xmlns:conv="clr-namespace:WpfApplication1"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <!-- conv is referenced in the "clr-namespace:WpfApplication1" namespace. It's bassically a referal to a converter I'm using -->
    <conv:IsNullConverter x:Key="isNullConverter"/>
    <Style TargetType="{x:Type TextBox}">
        <Style.Triggers>
            <!-- if the textbox is empty, then the setter should set the border colour to red-->
            <DataTrigger Binding="{Binding Words, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource isNullConverter}}" Value="True">
                <Setter Property="BorderBrush" Value="Red"/>
            </DataTrigger>
            <!-- If it has text inside it, setter should set the border colour to blue -->
            <DataTrigger Binding="{Binding Words, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource isNullConverter}}" Value="False">
                <Setter Property="BorderBrush" Value="Blue"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
<Grid>
    <TextBox x:Name="first" FontSize="14" TabIndex="1" Background="Black" BorderThickness="5" Foreground="White" Margin="29,10,132,272" />
</Grid>

因为数据触发器不可能单独查看一个值是否为非空,所以我必须添加一些代码来帮助它。

using System.Windows.Data;
using System.Globalization;
using System.ComponentModel;
namespace WpfApplication1
{

public class IsNullConverter : IValueConverter, INotifyPropertyChanged
{
    // The string that the 'conv:' checks against
    private string FOO;
    // The DataTriggrer is bound to 'Words'
    public string Words
    {
        get
        {
            return FOO;
        }
        set
        {
            if (FOO != value)
            {
                FOO = value;
                RaisePropertyChanged("Words");
            }
        }
    }
    private void RaisePropertyChanged(string prop)
    {
        if (PropertyChanged == null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    public string Error
    {
        get { return null; }
    }
    // This is the 'Convert' Parameter conv checks against. Here is the problem is
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //This checks against the FOO string at the top of this class. Not the FOO in 'Words' get & set string
        if (FOO == null)
        {
            value = true;
        }
        // So even if 'Words' raises the property changed, The origional FOO string remains unaffected.
        // So the Datatrigger is never fired
        if (FOO != null)
        {
            value = false;
        }
        return value;
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
    }
}

}

问题是,如果我在字符串FOO后面加上;

private string FOO = "Something";

Datatrigger在运行时触发并将轮廓颜色更改为蓝色。但是,我需要的颜色是基于文本框的内容,而不是我直接声明字符串作为。

我尝试将数据触发器绑定到'Words'字符串,但轮廓颜色仍然是红色,空或不。

和建议吗?如果有更好的方法,我真的不介意把这段代码完全颠倒过来。

数据触发器没有触发正确的字符串值

给你:

 <TextBox x:Name="first" FontSize="14" TabIndex="1" Background="Black" BorderThickness="5" Foreground="White" Margin="29,10,132,272">
            <TextBox.Style>
                <Style TargetType="TextBox">
                    <Setter Property="BorderBrush" Value="Blue"/>
                    <Style.Triggers>
                        <DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}}" Value="">
                            <Setter Property="BorderBrush" Value="Red"/>
                        </DataTrigger>
                        <DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}}" Value="{x:Null}">
                            <Setter Property="BorderBrush" Value="Red"/>
                        </DataTrigger>
                    </Style.Triggers>
                </Style>
            </TextBox.Style>
        </TextBox>

使用RelativeSource:

绑定TextBox.Text属性
<DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}, Converter={StaticResource isNullConverter}}" Value="True">
    <!--apropriate setter-->
</DataTrigger>

如果Text为空,则设置BorderBrush。当Text不为空时设置边框刷,只需使用正常的Setter,不使用DataTrigger

另外,请注意在ValueConverter中应该使用String.IsNullOrEmpty而不是普通的NULL比较。

您可以简化您的转换器,使其看起来像

public class IsNullConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return String.IsNullOrEmpty((string) value);
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new InvalidOperationException("IsNullConverter can only be used OneWay.");
    }
}

,然后样式绑定TextBox.Text通过转换器

<Window.Resources>
    <conv:IsNullConverter x:Key="isNullConverter"/>
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="BorderBrush" Value="Blue"/>
        <Style.Triggers>
            <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Text, Converter={StaticResource isNullConverter}}" Value="True">
                <Setter Property="BorderBrush" Value="Red"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Window.Resources>

这将工作,但只有当TextBox不集中时,默认模板将接管并更改BorderBrush。你可以让它工作,但是你需要改变默认模板,最简单的模板是在Style

中添加另一个Setter
<Setter Property="Template">
   <Setter.Value>
      <ControlTemplate TargetType="{x:Type TextBox}">
         <Border 
             BorderBrush="{TemplateBinding BorderBrush}" 
             Background="{TemplateBinding Background}" 
             BorderThickness="{TemplateBinding BorderThickness}">
            <ScrollViewer x:Name="PART_ContentHost"/>
         </Border>
      </ControlTemplate>
   </Setter.Value>
</Setter>