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

时间:2014-06-05 09:26:23

标签: c# wpf xaml

所以这就是主意。 如果文本框为空,则“DataTrigger”应将轮廓(BorderBrush)设置为红色。 如果文本框不为空/有文本;然后dataTrigger应该将BorderBrush设置为Blue。

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>

因为数据触发器不可能独立地查看某个值是否为null,所以我必须添加一些代码来帮助它做到这一点。

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'字符串,但轮廓颜色保持红色,空或不。

和建议?如果有更好的方法,我真的不介意我是否必须完全抛弃这些代码。

3 个答案:

答案 0 :(得分:1)

你走了:

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

答案 1 :(得分:0)

您可以简化转换器,使其类似于

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。您可以将其设为有效,但是您需要更改默认模板,其中最简单的模板将是Setter中的另一个Style

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

答案 2 :(得分:0)

使用TextBox.Text

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

如果BorderBrush为空,此触发器会设置Text。要在Text不为空时设置边框画笔,只需使用普通Setter,而不使用DataTrigger

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