为什么在不满足MultiDataTrigger条件时,Button.IsEnabled不会启动为false或重置为false?

时间:2013-06-28 16:01:19

标签: wpf xaml triggers multidatatrigger

我在办公室Taskpane中托管了一个用户控件,用于Word插件。

我已尝试按下DataTrigger to make WPF Button inactive until TextBox has value的答案和Cleanest way to bind a Button's visibility to the contents of two textboxes的答案,以便在两个文本框中只有非空内容时启用我的按钮。

转化器:

using System.Windows.Data;
using System.Globalization;

namespace RetrofitDocumentTool.Converter
{
    [ValueConversion(typeof(String), typeof(Boolean))]
    class StringToBooleanConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            string val = (string)value;
            bool result = !string.IsNullOrEmpty(val);
            return result;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException("This converter is oneway only.");
        }
    }
}

XAML:

<UserControl
    ...>

    <UserControl.Resources>
        <Style x:Key="ErrorLabel" TargetType="Label">
            ...
        </Style>

        <Style x:Key="StandardLabel" TargetType="Label">
            ...
        </Style>

        <Style TargetType="TextBox">
            ...
        </Style>

        <conv:StringToBooleanConverter x:Key="StringToBoolean"/>
    </UserControl.Resources>

    <DockPanel LastChildFill="True">
        <Border CornerRadius="8">
            <Grid
                ...
                ...
                ...

                <TextBox
                    Name="Serial_Number"
                    ...>
                </TextBox>
                <TextBox
                    Name="Job_Number"
                    ...>
                </TextBox>

                <Button
                    ...>

                    <Button.Style>
                        <Style TargetType="{x:Type Button}">
                            <Style.Triggers>
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding Text, ElementName=Serial_Number, Converter={StaticResource StringToBoolean}}" Value="True"/>
                                        <Condition Binding="{Binding Text, ElementName=Job_Number, Converter={StaticResource StringToBoolean}}" Value="True"/>
                                    </MultiDataTrigger.Conditions>
                                    <Setter Property="IsEnabled" Value="True"/>
                                </MultiDataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Button.Style>

                </Button>
            </Grid>
        </Border>
    </DockPanel>

</UserControl>

问题:

当文本框中有某些内容时,转换器返回true,如果两个文本框中都包含某些内容,则两个转换器都会触发,并且应该应用setter。我知道这是因为我可以在setter中将IsEnabled属性设置为False,它将取消激活初始状态的按钮。

反向发生:将IsEnabled属性设置为True不会启用按钮,其中初始状态已停用(我通过将IsEnabled属性设置为False直接执行此操作)在按钮上)。我认为这将作为默认状态,并且Setter会覆盖它。情况似乎并非如此。

我注意到了一些奇怪的事情:

第二个条件似乎直到第一个条件才开始。即,如果我在触摸第一个文本框之前将某些数据输入到第二个文本框中,则转换器根本不会触发。如果我认为在第一个文本框中输入数据,两个转换器都会触发。

有没有办法只在文本框中存在数据时启用按钮?我是否真的需要写出每种情况的组合:( True / True = Enabled,True / False = Disabled,False / True = Disabled,False / False = Disabled)?这是我的一个错字或一些愚蠢的逻辑错误的情况吗?我现在无法用不偏不倚的目光看着这个。

1 个答案:

答案 0 :(得分:2)

尝试将Style更新为

<Style TargetType="{x:Type Button}">
  <!-- New Bit -->
  <Setter Property="IsEnabled" Value="False"/>
  <!-- End of New Bit -->
    <Style.Triggers>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding Text, ElementName=Serial_Number, Converter={StaticResource StringToBoolean}}" Value="True"/>
                <Condition Binding="{Binding Text, ElementName=Job_Number, Converter={StaticResource StringToBoolean}}" Value="True"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="IsEnabled" Value="True"/>
        </MultiDataTrigger>
    </Style.Triggers>
</Style>
  

我通过直接在按钮

上将IsEnabled属性设置为False来完成

如果在元素上设置属性,那么WPF优先级将使该属性的任何Trigger或默认设置器几乎无效。

最后,如果您使用Trigger修改属性并确保没有在元素上提及该属性,那么始终最好为属性指定默认值本身。

在您的具体情况下,您甚至可以在不使用转换器的情况下执行此操作。

<StackPanel xmlns:sys="clr-namespace:System;assembly=mscorlib">
  <TextBox x:Name="tbOne" />
  <TextBox x:Name="tbTwo" />
  <Button Content="Some Button">
    <Button.Style>
      <Style TargetType="{x:Type Button}">
        <Setter Property="IsEnabled"
                Value="True" />
        <Style.Triggers>
          <DataTrigger Binding="{Binding ElementName=tbOne,
                                          Path=Text}"
                        Value="{x:Static sys:String.Empty}">
            <Setter Property="IsEnabled"
                    Value="False" />
          </DataTrigger>
          <DataTrigger Binding="{Binding ElementName=tbTwo,
                                          Path=Text}"
                        Value="{x:Static sys:String.Empty}">
            <Setter Property="IsEnabled"
                    Value="False" />
          </DataTrigger>
        </Style.Triggers>
      </Style>
    </Button.Style>
  </Button>
</StackPanel>