我采用了似乎是使用IDataErrorInfo接口和样式验证WPF中文本框的标准方法,如下所示。但是,如何在页面无效时禁用“保存”按钮?这是通过触发器以某种方式完成的吗?
Default Public ReadOnly Property Item(ByVal propertyName As String) As String Implements IDataErrorInfo.Item
Get
Dim valid As Boolean = True
If propertyName = "IncidentCategory" Then
valid = True
If Len(IncidentCategory) = 0 Then
valid = False
End If
If Not valid Then
Return "Incident category is required"
End If
End If
Return Nothing
End Get
End Property
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="3" />
<Setter Property="Height" Value="23" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="MyAdorner" />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
答案 0 :(得分:38)
有几件事:
首先,我建议使用RoutedCommand ApplicationCommands.Save
来实现保存按钮的处理。
如果您还没有签出WPF Command模型,可以获得独家新闻here。
<Button Content="Save" Command="Save">
现在,要实现该功能,您可以添加命令绑定到Window / UserControl或Button本身:
<Button.CommandBindings>
<CommandBinding Command="Save"
Executed="Save_Executed" CanExecute="Save_CanExecute"/>
</Button.CommandBindings>
</Button>
在代码中实现这些:
private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
{
}
private void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
}
在Save_CanExecute
中,根据文本框中绑定的有效性设置e.CanExecute
。
如果您想使用MVVM(Model-View-ViewModel)设计模式实现,请查看Josh Smith在CommandSinkBinding上的帖子。
最后一点说明:如果您希望在更改TextBox
中的值后立即更新启用/禁用,请在UpdateSourceTrigger="PropertyChanged"
的绑定上设置TextBox
。 / p>
编辑:如果你想根据控件中的所有绑定验证/无效,这里有一些建议。
1)您已经在实施IDataErrorInfo
。尝试实现IDataErrorInfo.Error
属性,使其返回对您绑定的所有属性无效的字符串。这仅在整个控件绑定到单个数据对象时才有效。设置e.CanExecute = string.IsNullOrEmpty(data.Error);
2)使用反射获取相关控件上的所有公共静态DependencyProperties。然后在每个属性的循环中调用BindingOperations.GetBindingExpression(relevantControl, DependencyProperty)
,以便您可以测试验证。
3)在构造函数中,手动创建嵌套控件上所有绑定属性的集合。在CanExecute中,使用DependencyObject
来获取表达式,然后检查DepencyProperty
,遍历此集合并验证每个BindingOperation.GetBindingExpression()
/ BindingExpression.HasError
组合。
答案 1 :(得分:1)
我为此创建了附加属性:
public static class DataErrorInfoHelper
{
public static object GetDataErrorInfo(ButtonBase obj)
{
return (object)obj.GetValue(DataErrorInfoProperty);
}
public static void SetDataErrorInfo(ButtonBase obj, object value)
{
obj.SetValue(DataErrorInfoProperty, value);
}
// Using a DependencyProperty as the backing store for DataErrorInfo. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataErrorInfoProperty =
DependencyProperty.RegisterAttached("DataErrorInfo", typeof(object), typeof(DataErrorInfoHelper), new PropertyMetadata(null, OnDataErrorInfoChanged));
private static void OnDataErrorInfoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var button = d as ButtonBase;
if (button.Tag == null)
button.Tag = new DataErrorInfoContext { Button = button };
var context = button.Tag as DataErrorInfoContext;
if(e.OldValue != null)
{
PropertyChangedEventManager.RemoveHandler(((INotifyPropertyChanged)e.OldValue), context.Handler, string.Empty);
}
var inotify = e.NewValue as INotifyPropertyChanged;
if (inotify != null)
{
PropertyChangedEventManager.AddHandler(inotify, context.Handler, string.Empty);
context.Handler(inotify, new PropertyChangedEventArgs(string.Empty));
}
}
private class DataErrorInfoContext
{
public ButtonBase Button { get; set; }
public void Handler(object sender, PropertyChangedEventArgs e)
{
var dei = sender as IDataErrorInfo;
foreach (var property in dei.GetType().GetProperties())
{
if (!string.IsNullOrEmpty(dei[property.Name]))
{
Button.IsEnabled = false;
return;
}
}
Button.IsEnabled = string.IsNullOrEmpty(dei.Error);
}
}
}
我在我的表单上使用它:
<TextBlock Margin="2">e-mail:</TextBlock>
<TextBox Margin="2" Text="{Binding Email, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>
<!-- other databindings--->
<Button Margin="2" local:DataErrorInfoHelper.DataErrorInfo="{Binding}" Commands="{Binding SaveCommand}">Create account</Button>