我在办公室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)?这是我的一个错字或一些愚蠢的逻辑错误的情况吗?我现在无法用不偏不倚的目光看着这个。
答案 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>