上次写了焦点控制,这次讲一下,校验和错误提示。
wpf自带有ValidationRule
第一种:写说下ValidationRule的使用情况。
继承ValidationRule, override Validate方法。
然后xaml里
<Style.Triggers> <MultiTrigger> <MultiTrigger.Conditions> <Condition Property="Validation.HasError" Value="True" /> <Condition Property="IsFocused" Value="True" /> </MultiTrigger.Conditions> <Setter Property="Validation.ErrorTemplate"> <Setter.Value> <ControlTemplate> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition /> </Grid.RowDefinitions> <AdornedElementPlaceholder Name="MyAdorner" /> <Border Grid.Row="1" Height="20" Margin="10,-1,0,0" Background="#FFE2402F" CornerRadius="4" Opacity="30"> <Border.Effect> <DropShadowEffect ShadowDepth="0" /> </Border.Effect> <TextBlock Margin="8,0" FontSize="11" VerticalAlignment="Center" Foreground="White" Text="{Binding ElementName=MyAdorner, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" TextWrapping="Wrap" /> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> <Setter Property="Foreground" Value="red" /> </MultiTrigger> <Trigger Property="Validation.HasError" Value="True"> <Setter Property="Foreground" Value="red" /> </Trigger> </Style.Triggers>
第二种:IDataErrorInfo类,可以在定义的ViewModel里继承,
主要两个方法
public string Error public string this[string columnName]
xaml使用情况同第一中种。
但是前面几种可以提示错误信息,但是有错误时,无法不让焦点移动。
下面我说说第三种方法:
首先定义接口:
public interface IContextValidation { ValidationResult Validate(DependencyObject sender); } public interface IContextValidationPolicy { void Run(DependencyObject sender, object content); }
然后扩展接口
public abstract class CodeValidationBase : IContextValidation { public string MethodName { get; set; } } public abstract class CodePolicyBase : IContextValidationPolicy { public string MethodName { get; set; } public abstract void Run(System.Windows.DependencyObject sender, object content); }
接下来实现接口
public class ClientCodeValidation : CodeValidationBase { public override ValidationResult Validate(DependencyObject sender) { Requires.NotNull(sender, "sender"); Requires.NotNull(this.MethodName, "MethodName"); object obj=null; return (ValidationResult)sender.SafeInvoke(new Func<ValidationResult>(() => { var page = this.GetVisualParent<Window>(sender as Visual); if (sender is TextBox) { obj = ((TextBox)sender).Text; } else if (sender is DataGridCell) { var temp = (sender as DataGridCell).Content; if (temp is TextBox) { obj = ((TextBox)temp).Text; } else if (temp is TextBlock) { obj = ((TextBlock)temp).Text; } } else { var textBoxBase = this.GetVisualChild<TextBox>(sender as Visual); if (textBoxBase != null) { obj = ((TextBox)textBoxBase).Text; } } if (page == null) { throw new InvalidOperationException("Cannot find page which owns sender"); } return page.ReflectCallInstanceMethod<ValidationResult>( this.MethodName, new Type[] { typeof(object) }, obj); })); } }
public class KeepFocusPolicy : IContextValidationPolicy { public void Run(System.Windows.DependencyObject sender, object content) { Requires.NotNull(sender, "sender"); var element = sender as FrameworkElement; if (element == null) { throw new ArgumentException("sender must be FrameworkElement", "sender"); } element.SafeInvoke(() => element.Focus()); } } public sealed class ShowTipPolicy : IContextValidationPolicy { public TipAdornerPlacement Placement { get; set; } public void Run(System.Windows.DependencyObject sender, object content) { var element = sender as FrameworkElement; if (element == null) return; sender.SafeInvoke(() => { var message = content == null ? "输入错误" : content.ToString(); element.ShowTipAdorner(Placement, message); }); } }
最后我们就可以在焦点移动前,去做判断了:
var myDataGridTextColumn = currentCellContainer.Column as MyDataGridTextColumn; if (myDataGridTextColumn != null) { var validations = myDataGridTextColumn.Validations; var errorPolicies = myDataGridTextColumn.ErrorPolicies; bool hasError = false; object errMessage = null; validations.ForEach(o => { var result = o.Validate(focuseElement); if (!result.IsValid) { hasError = true; errMessage = result.ErrorContent; } }); if (hasError) { errorPolicies.ForEach(o => o.Run(focuseElement, errMessage)); this.SetValue(CurrentCellProperty, new DataGridCellInfo(currentCellContainer)); //this.SetValue(MyCurrentCellProperty, currentCellContainer); var temp = this.CurrentCell; //focuseElement.Focus(); return; } }
xmal里使用:
<local:MyDataGridTextColumn Header="BBB" Width="100" Binding="{Binding B}"> <local:MyDataGridTextColumn.Validations> <local:ClientCodeValidation MethodName="Validation"/> </local:MyDataGridTextColumn.Validations> <local:MyDataGridTextColumn.ErrorPolicies> <local:ShowTipPolicy Placement="Right" /> <local:KeepFocusPolicy /> </local:MyDataGridTextColumn.ErrorPolicies> </local:MyDataGridTextColumn>
校验事件,写在前台,校验的时候会使用反射,调用。
public ValidationResult Validation(object value) { if ((string)value == "5") { return new ValidationResult(false, "不能为5"); } return new ValidationResult(true, string.Empty); }