我有一个表单,其中包含两个密码字段——用户输入密码的一个字段和用户必须重新输入确认密码的另一个字段。验证用于确认两个密码是否匹配——如果匹配,则启用按钮以允许用户继续:
<PasswordBox Name="P1Box" src:PasswordBoxAssistant.BindPassword="True">
<src:PasswordBoxAssistant.BoundPassword>
<Binding Source="{StaticResource mybinding}" Path="Password.P1" UpdateSourceTrigger="PropertyChanged" Mode="TwoWay">
<Binding.ValidationRules>
<DataErrorValidationRule ValidatesOnTargetUpdated="True"/>
</Binding.ValidationRules>
</Binding>
</src:PasswordBoxAssistant.BoundPassword>
</PasswordBox>
按钮样式:
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding ElementName=P1Box, Path=(Validation.HasError)}" Value="false"/>
</MultiDataTrigger.Conditions>
<Setter Property="IsEnabled" Value="true"/>
</MultiDataTrigger>
</Style.Triggers>
我的问题是用户可以更改第一个框中的密码,但它不会强制第二个密码框重新验证。例如,如果第一个密码输入为“password”,并且用户在第二个框中输入“password”,则验证通过,并启用按钮。如果用户然后将原始密码框更改为“PASSWORD”,则两个框都保持验证 - 原始框没有约束非空密码,第二个框没有强制验证更新。
我的密码框使用附加属性这里概述的方法允许绑定到密码。因此,我找不到一种在代码后台中访问它的方法(因为PasswordBox.Password本身不是依赖属性),就像这个解决方案所示的方式一样。或者,也许它只适用于附加属性 - 下面的代码什么也没做:
P2Box.GetBindingExpression(PasswordBoxAssistant.BoundPassword).UpdateSource();
我有一个自定义类,继承了IDataErrorInfo接口,以允许在两个控件之间进行验证 - 绑定是一个PasswordData对象,密码框设置为PasswordData.P1和PasswordData.P2:
public class PasswordData : IDataErrorInfo
{
public string P1 { get; set; }
public string P2 { get; set; }
public string Error { get { return string.Empty; } }
public string this[string propertyName]
{
get
{
string ret;
if (propertyName == "P1")
{
if (P1 == null || P1 == "")
ret = "Password cannot be null or empty.";
else
ret = "";
}
else if (propertyName == "P2")
{
if (P2 == null || P2 == "")
ret = "Password cannot be null or empty.";
else if (P2 != P1)
ret = "The passwords do not match.";
else
ret = "";
}
return ret;
}
}
}
我尝试在PasswordChanged事件中插入,创建一个新的PasswordData,并重新分配绑定。这解决了验证问题,但密码框中的插入符号总是在最开始的位置,破坏了任何已输入的数据。
我希望有一个仅限于xaml的解决方案,但是代码后台也完全可以接受。如果有影响,我正在使用.Net 4.0。
编辑:好吧,事实证明我在xaml中打错了事件处理程序,解决方案实际上是可行的。
private void PasswordChanged(object sender, RoutedEventArgs e)
{
binding.Pass.P1 = ((PasswordBox)sender).Password;
P2Box.GetBindingExpression(PasswordBoxAssistant.BoundPassword).UpdateSource();
}
由于事件在绑定更新之前触发,因此我必须手动更新绑定。
我很想知道是否有一种适当的、只使用XAML的方法,使用验证规则、IDataErrorInfo或其他方式在控件之间建立绑定,而无需挂钩到事件并手动更新。