2016-03-21 245 views
4

我正在使用Visual Studio 2015更新1构建MVVM Light WPF应用程序。我有以下两个搜索字段:cmbSearchColumntxtSearchValue。当用户单击搜索按钮时,它们都不能为空。请注意,我已为这两个字段设置了ValidationRules点击搜索按钮触发验证

下面是相关的XAML:

<TextBlock Grid.Row="1" 
      Grid.Column="0" 
      Style="{StaticResource FieldLabel}"> 
    Search Column 
</TextBlock> 
<StackPanel Grid.Row="1" 
      Grid.Column="1" 
      Style="{StaticResource ValidationStackPanel}"> 
    <ComboBox x:Name="cmbSearchColumn" 
       DisplayMemberPath="MemberName" 
       IsEditable="True" 
       ItemsSource="{Binding SearchColumns}" 
       SelectedValuePath="MemberValue" 
       Style="{StaticResource ComboBoxStyle}"> 
     <ComboBox.SelectedItem> 
      <Binding Mode="TwoWay" 
        Path="SelectedColumn}" 
        UpdateSourceTrigger="Explicit"> 
       <Binding.ValidationRules> 
        <helpers:NotEmptyStringValidationRule 
    Message="Search Column cannot be blank." ValidatesOnTargetUpdated="True" /> 
       </Binding.ValidationRules> 
      </Binding> 
     </ComboBox.SelectedItem> 
    </ComboBox> 
    <TextBlock Style="{StaticResource FieldLabelError}" 
    Text="{Binding (Validation.Errors)[0].ErrorContent, ElementName=cmbSearchColumn}" /> 
</StackPanel> 
<TextBlock Grid.Row="2" 
      Grid.Column="0" 
      Padding="0 0 9 9" 
      Style="{StaticResource FieldLabel}"> 
    Search Value 
</TextBlock> 
<StackPanel Grid.Row="1" 
      Grid.Column="1" 
      Style="{StaticResource ValidationStackPanel}"> 
    <TextBox x:Name="txtSearchValue" Style="{StaticResource FieldTextBox}"> 
     <TextBox.Text> 
      <Binding Mode="TwoWay" 
        Path="SearchValue" 
        UpdateSourceTrigger="Explicit"> 
       <Binding.ValidationRules> 
        <helpers:NotEmptyStringValidationRule 
    Message="Search Value cannot be blank." ValidatesOnTargetUpdated="True" /> 
       </Binding.ValidationRules> 
      </Binding> 
     </TextBox.Text> 
    </TextBox> 
    <TextBlock Style="{StaticResource FieldLabelError}" 
    Text="{Binding (Validation.Errors)[0].ErrorContent, ElementName=txtSearchValue}" /> 
</StackPanel> 
<Button Grid.Row="4" 
    Grid.Column="1" 
    Command="{Binding SearchEmployeesRelayCommand}" 
    Content="Search" 
    Style="{StaticResource FieldButton}" /> 

当应用程序加载时,它会立即显示错误的字段旁边,说他们不能为空。但是,只有当用户单击“搜索”按钮时,我才需要触发验证。

我该怎么做?谢谢。

+2

我没有看到你所张贴的全部代码,但我想你应该简单地使用'禁用搜索按钮ICommand.CanExecute()'函数(当你的验证条件失败时返回false) - 你也应该为你使用的属性订阅viewmodel的更改并相应地提升'ICommand.CanExecuteChanged' – Maverik

+0

谢谢,@Maverik。去查看这些语法,看看如何正确地做到这一点:) – Alex

+0

@Maverik我认为OP要求相反。如果验证失败,他不想禁用该按钮。他希望验证错误消息仅在单击该按钮时才显示。 –

回答

4

您可以使用INotifyDataErrorInfo

注意INotifyDataErrorInfo作品与自定义规则添加到绑定。自定义规则和RelayCommand的代码不包含在此答案中。

样品实施:

using System; 
using System.Collections; 
using System.Collections.Concurrent; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Diagnostics; 

public class PropertyErrors : INotifyDataErrorInfo 
{ 
    private static readonly IReadOnlyList<object> EmptyErrors = new object[0]; 
    private readonly Action<DataErrorsChangedEventArgs> ownerOnErrorsChanged; 
    private readonly Type type; 
    private readonly ConcurrentDictionary<string, List<object>> propertyErrors = new ConcurrentDictionary<string, List<object>>(); 

    public PropertyErrors(INotifyDataErrorInfo owner, Action<DataErrorsChangedEventArgs> ownerOnErrorsChanged) 
    { 
     this.ownerOnErrorsChanged = ownerOnErrorsChanged; 
     this.type = owner.GetType(); 
    } 

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; 

    public bool HasErrors => this.propertyErrors.Count > 0; 

    public IEnumerable GetErrors(string propertyName) 
    { 
     Debug.Assert(this.type.GetProperty(propertyName) != null, $"The type {this.type.Name} does not have a property named {propertyName}"); 
     List<object> errors; 
     return this.propertyErrors.TryGetValue(propertyName, out errors) 
      ? errors 
      : EmptyErrors; 
    } 

    public void Add(string propertyName, object error) 
    { 
     Debug.Assert(this.type.GetProperty(propertyName) != null, $"The type {this.type.Name} does not have a property named {propertyName}"); 
     this.propertyErrors.AddOrUpdate(
      propertyName, 
      _ => new List<object> { error }, 
      (_, errors) => UpdateErrors(error, errors)); 

     this.OnErrorsChanged(new DataErrorsChangedEventArgs(propertyName)); 
    } 

    public void Remove(string propertyName, Predicate<object> filter) 
    { 
     Debug.Assert(this.type.GetProperty(propertyName) != null, $"The type {this.type.Name} does not have a property named {propertyName}"); 
     List<object> errors; 
     if (this.propertyErrors.TryGetValue(propertyName, out errors)) 
     { 
      errors.RemoveAll(filter); 
      if (errors.Count == 0) 
      { 
       this.Clear(propertyName); 
      } 
     } 
    } 

    public void Clear(string propertyName) 
    { 
     Debug.Assert(this.type.GetProperty(propertyName) != null, $"The type {this.type.Name} does not have a property named {propertyName}"); 
     List<object> temp; 
     if (this.propertyErrors.TryRemove(propertyName, out temp)) 
     { 
      this.OnErrorsChanged(new DataErrorsChangedEventArgs(propertyName)); 
     } 
    } 

    protected virtual void OnErrorsChanged(DataErrorsChangedEventArgs e) 
    { 
     this.ErrorsChanged?.Invoke(this, e); 
     this.ownerOnErrorsChanged(e); 
    } 

    private static List<object> UpdateErrors(object error, List<object> errors) 
    { 
     if (!errors.Contains(error)) 
     { 
      errors.Add(error); 
     } 

     return errors; 
    } 
} 
using System; 
using System.Collections; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using System.Windows; 
using System.Windows.Input; 

public class ViewModel : INotifyPropertyChanged, INotifyDataErrorInfo 
{ 
    private readonly PropertyErrors errors; 
    private string searchText; 

    public ViewModel() 
    { 
     this.SearchCommand = new RelayCommand(this.Search); 
     this.errors = new PropertyErrors(this, this.OnErrorsChanged); 
    } 

    public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged; 

    public event PropertyChangedEventHandler PropertyChanged; 

    public string SearchText 
    { 
     get { return this.searchText; } 
     set 
     { 
      if (value == this.searchText) 
      { 
       return; 
      } 

      this.searchText = value; 
      this.errors.Clear(nameof(this.SearchText)); 
      this.OnPropertyChanged(); 
     } 
    } 

    public bool HasErrors => this.errors.HasErrors; 

    public ICommand SearchCommand { get; } 

    public IEnumerable GetErrors(string propertyName) => this.errors.GetErrors(propertyName); 

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    private void Search() 
    { 
     if (string.IsNullOrEmpty(this.searchText)) 
     { 
      this.errors.Add(nameof(this.SearchText), "Search text cannot be empty"); 
      return; 
     } 

     MessageBox.Show("searching"); 
    } 

    protected virtual void OnErrorsChanged(DataErrorsChangedEventArgs e) 
    { 
     this.ErrorsChanged?.Invoke(this, e); 
    } 
} 
<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition /> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="Auto" /> 
     <ColumnDefinition /> 
     <ColumnDefinition /> 
    </Grid.ColumnDefinitions> 
    <TextBlock Grid.Row="0" 
       Grid.Column="0" 
       Text="Search text" /> 
    <TextBox x:Name="SearchTextBox" 
      Grid.Row="0" 
      Grid.Column="1"> 
     <TextBox.Text> 
      <Binding Path="SearchText" 
        UpdateSourceTrigger="PropertyChanged"> 
       <Binding.ValidationRules> 
        <local:MustStartWithValidationRule StartsWith="a" /> 
       </Binding.ValidationRules> 
      </Binding> 
     </TextBox.Text> 
    </TextBox> 
    <ItemsControl Grid.Row="0" 
        Grid.Column="2" 
        Margin="6,0,0,0" 
        ItemsSource="{Binding Path=(Validation.Errors), 
             ElementName=SearchTextBox}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate DataType="{x:Type ValidationError}"> 
       <TextBlock Foreground="Red" 
          Text="{Binding ErrorContent}" /> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 

    <Button Grid.Row="1" 
      Grid.Column="1" 
      Command="{Binding SearchCommand}" 
      Content="Search" /> 
</Grid> 
-1
First name:<br> 
    <input type="text" name="firstname" id="Fname" class="required" maxlength="50"> 
    <br> 
    Last name:<br> 
    <input type="text" name="lastname" id="lname" class="required" maxlength="50"> 
    <br> 
    Email:<br> 
    <input type="email" name="emailid" id="email" class="required" maxlength="50"> 
    <br> 
    Phone No:-<br> 
    <input type="text" maxlength="10" id="phoneno" class="required" pattern="[0-9]{10}" > 
    <br> 
    Address:<br> 

<textarea rows="5" cols="25" id="address" class="required" maxlength="500"> 

</textarea> 
    <br><br >&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 
<input type="button" value="submit"`onclick="validate()" />