1

我在办公室任务窗格中托管了一个用于 Word 插件的用户控件。

我尝试按照DataTrigger 的答案使 WPF Button 处于非活动状态,直到 TextBox 具有值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。我知道会发生这种情况,因为我可以IsEnabled在 setter 中将属性设置为 False,它会停用初始状态被激活的按钮。

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

我注意到的一些奇怪现象:

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

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

4

1 回答 1

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该属性的任何 's 或默认设置器几乎处于非活动状态。

最后,如果您使用 a来修改属性,最好始终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>
于 2013-06-28T16:04:38.397 回答