我是WPF的新手,在网上找不到解决方案。我的问题是,我希望我的按钮只有在四个文本框不会有有效性错误时才启用。我的代码是:
<Button Content="Action" Click="Action_Click" >
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource ValCon}">
<Binding ElementName="textBox1" />
<Binding ElementName="textBox2"/>
<Binding ElementName="textBox3"/>
<Binding ElementName="textBox4"/>
</MultiBinding>
</Button.IsEnabled>
</Button>
和我的多值转换器就像:
class ValidityConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
bool b = true;
foreach (var x in values)
{
TextBox y = x as TextBox;
if (Validation.GetHasError(y))
{
b = false;
break;
}
}
return b;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
我注意到这只在开始时有效。当用户修改其中一个文本框时,它不会。我的值转换器需要实现INotifyPropertyChange吗?在WPF中做这样的事情的正确解决方案是什么?谢谢你的帮助。
编辑
我已经做了这样的事情,它正在工作:
<Button Click="Button_Click" >
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=textBox}" Value="False"/>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=textBox1}" Value="False"/>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=textBox2}" Value="False"/>
<Condition Binding="{Binding Path=(Validation.HasError), ElementName=textBox3}" Value="False"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="True"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
我所做的是使用您的MultiTrigger,解决方案,但在我的情况下,我想要一个按钮得到激活只有当3个文本框的长度为零,所以我的解决方案与下面的代码工作。
<Button.Style>
<Style TargetType="Button">
<Setter Property="IsEnabled" Value="True"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Text.Length, ElementName=activationKeyTextbox}" Value="0"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="False"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Text.Length, ElementName=serialDayStartbox}" Value="0"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="False"/>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=Text.Length, ElementName=serialNumdaysbox}" Value="0"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="False"/>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
我不会实现multivalueconverter,因为我们这里没有转换任何东西。BindingGroup可以满足您的目的。
同样有效的方法使用MVVM/INotifyPropertyChanged可以如下:-
- 将按钮的IsEnabled属性绑定到布尔属性(比如IsValid)。
- 将所有文本框绑定到不同的属性。
- OnPropertyChange的任何这些文本框,调用一个共同的功能(说Validate())
- IsValid可以根据Validate()设置为true或false,这将反过来切换(启用/禁用)按钮的状态。
我知道这是旧的,但我是在一个类似的需要,不想写一个绑定组和验证…注意,这是我的第一个wpf应用程序和第一次使用mvvm!
<Button Name="AddBtn" Content="Add" Grid.Row="2" Grid.Column="2" Height="30" Width="100" Command="{Binding AddCmd}" CommandParameter="{Binding Pending}" >
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource multiButtonEnabled}" >
<Binding ElementName="tb1" Path="(Validation.Errors)[0]" />
<Binding ElementName="tb2" Path="(Validation.Errors)[0]" />
<Binding ElementName="tb3" Path="(Validation.Errors)[0]" />
</MultiBinding>
</Button.IsEnabled>
</Button>
转换器看起来像这样
[ValueConversion(typeof(ValidationError), typeof(bool))]
class TxtBoxMultiEnableConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
int i=0;
foreach (var item in values)
{
if (item as ValidationError != null)
{
i++;
}
}
if (i!=0)
{
return false;
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException();
}
}
我使用IDataErrorInfo来捕获模型中的错误,并绑定到double类型。WPF很好,在绑定时为您抛出解析错误,但它们并没有真正给您提供一种方法来挂钩到它们以更改显示给用户的消息,或者给您一个属性来检查是否有错误标记,这很烦人,但这让您可以在解析中捕获错误,而不必在验证规则中检查解析错误。我知道我的无知正在显现,但我们都必须从某个地方开始!
正如Mike所说,文本框没有改变。
你应该绑定文本框。文本属性。
在你的例子中:
<Button Content="Action" Click="Action_Click" >
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource ValCon}">
<Binding ElementName="textBox1" Path="Text"/>
<Binding ElementName="textBox2" Path="Text" />
<Binding ElementName="textBox3" Path="Text"/>
<Binding ElementName="textBox4" Path="Text"/>
</MultiBinding>
</Button.IsEnabled>
</Button>
免责声明
这是我的第一个StackOverflow答案,所以它可能是不准确的,或者需要调整以遵循StackOverflow协议。
关于这个评论:https://stackoverflow.com/a/23504690/14654255(不能直接评论)
我已经尝试使用这个建议;但是,如果没有另一种机制来手动更新MultiBinding,这是不够的。我的建议是:
FormConverter.cs:
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApp.Converters
{
/// <summary>
/// This class will be used to determine whether the form submission button should be enabled
/// </summary>
[ValueConversion(typeof(Control), typeof(bool))]
public class FormConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
foreach (Control control in values)
{
//Relevant inside the scope of the current iteration only
string text = null;
//Any validation error
if (Validation.GetHasError(control))
return false;
//No value selected
if (control is DatePicker datePicker)
if (datePicker.SelectedDate == DateTime.Today)
return false;
else continue;
if (control is ComboBox comboBox)
if (comboBox.SelectedIndex == -1)
return false;
else continue;
//Left blank
if (control is TextBox textBox)
text = textBox.Text;
else if (control is PasswordBox passwordBox)
text = passwordBox.Password;
if (text != null && text.Length == 0)
return false;
}
return true;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotSupportedException();
}
}
}
MainWindow.xaml.cs:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace WpfApp
{
class MainWindow : Window
{
private MultiBindingExpression buttonBinding = null;
public MainWindow()
{
InitializeComponent();
buttonBinding = BindingOperations.GetMultiBindingExpression(button, button.IsEnabledProperty);
}
private void UpdateButton(object sender, RoutedEventArgs e)
{
if (registerButtonBinding == null)
return;
buttonBinding.UpdateTarget();
}
}
}
MainWindow.xaml:
<Window x:Class="WpfApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:WpfApp.Converters">
<Window.Resources>
<converters:formConverter x:Key="formConverter"/>
</Window.Resources>
<StackPanel HorizontalAlignment="Center">
<TextBlock Text="First name"/>
<TextBox x:Name="firstNameTextBox"/>
<Button x:Name="button">
<Button.IsEnabled>
<MultiBinding Converter="{StaticResource formConverter}">
<Binding ElementName="firstName"/>
</MultiBinding>
</Button.IsEnabled>
</Button>
</StackPanel>
</Window>
来源:
- https://stackoverflow.com/a/23504690/14654255
- https://stackoverflow.com/a/19356651/14654255
- https://stackoverflow.com/a/5676257/14654255