[英]How to bind to TextBox.Text in local ValidationRule class
This is my XAML file: 这是我的XAML文件:
<Window x:Class="WpfListView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfListView"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView Margin="10" Name="lvUsers">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="150" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Margin="0,0,5,0">
<Binding Path="Mail" Mode="TwoWay">
<Binding.ValidationRules>
<local:NameValidation>
<local:NameValidation.Params>
<local:NameValidationParameters
OriginalTree="{Binding Source={x:Reference lvUsers}}"
OriginalName="{Binding RelativeSource={RelativeSource Self}}"/> <!-- I want the OriginalName to be TextBox.Text-->
</local:NameValidation.Params>
</local:NameValidation>
</Binding.ValidationRules>
</Binding>
</TextBox>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
This is my MainWindow
class: 这是我的
MainWindow
类:
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<User> items = new List<User>();
items.Add(new User() { Name = "John Doe", Age = 42, Mail = "john@doe-family.com" });
items.Add(new User() { Name = "Jane Doe", Age = 39, Mail = "jane@doe-family.com" });
items.Add(new User() { Name = "Sammy Doe", Age = 7, Mail = "sammy.doe@gmail.com" });
lvUsers.ItemsSource = items;
}
}
And this is my ValidationRule
class: 这是我的
ValidationRule
类:
public class NameValidationParameters : DependencyObject
{
public ListView OriginalTree
{
get { return (ListView)this.GetValue(OriginalTreeProperty); }
set { this.SetValue(OriginalTreeProperty, value); }
}
public string OriginalName
{
get { return (string)this.GetValue(OriginalNameProperty); }
set { this.SetValue(OriginalNameProperty, value); }
}
public static readonly DependencyProperty OriginalTreeProperty
= DependencyProperty.Register(nameof(OriginalTree), typeof(ListView),
typeof(NameValidationParameters));
public static readonly DependencyProperty OriginalNameProperty
= DependencyProperty.Register(nameof(OriginalName), typeof(string),
typeof(NameValidationParameters));
}
public class NameValidation : ValidationRule
{
public string ErrorMessage
{ get; set; }
public NameValidationParameters Params { get; set; }
public override ValidationResult Validate(object value, CultureInfo cultureInfo)
{
ValidationResult lResult = null;
return lResult;
}
}
As you can see, when the NameValidation.Validate
is called, I want NameValidation.Params
to be populated with correct variables: 如您所见,当调用
NameValidation.Validate
时,我希望使用正确的变量填充NameValidation.Params
:
NameValidation.Params.OriginalTree
should be the original ListView
. NameValidation.Params.OriginalTree
应该是原始的ListView
。 This I can get. NameValidation.Params.OriginalName
should be the current TextBox's Text. NameValidation.Params.OriginalName
应该是当前TextBox的Text。 In this case, it is bound to Mail
, so I would expect to see that it is the email address like john@doe-family.com
. Mail
,因此我希望看到它是类似于john@doe-family.com
的电子邮件地址。 However I can't get this out; NameValidation.Params.OriginalName
is "WpfListView.NameValidationParameters" NameValidation.Params.OriginalName
是“ WpfListView.NameValidationParameters” Also, I want to be able to access the current index in the list inside the NameValidation.Validate
method. 另外,我希望能够访问
NameValidation.Validate
方法内列表中的当前索引。 How can I get it? 我怎么才能得到它?
As mentioned elsewhere, Validation rules do not hold or inherit a DataContext this will prevent binding from working as expected if you try to declare everything inline. 如在其他地方提到的,验证规则不保存或继承DataContext,如果您尝试内联声明所有内容,这将阻止绑定按预期工作。 Instead, declare your bindable rule options as a resource and set the property on your custom rule using a StaticBinding.
而是将可绑定规则选项声明为资源,并使用StaticBinding在自定义规则上设置属性。
I've modified your TextBox to add a resource parameter: 我已修改您的TextBox以添加资源参数:
<TextBox Grid.Column="0" Margin="0,0,5,0" x:Name="box1">
<TextBox.Resources>
<local:NameValidationParameters OriginalName="{Binding Mail}" OriginalTree="{Binding Source={x:Reference lvUsers}}" x:Key="Parameters"/>
</TextBox.Resources>
<TextBox.Text>
<Binding Path="Mail" Mode="TwoWay">
<Binding.ValidationRules>
<local:NameValidation Params="{StaticResource Parameters}"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
And NameValidationParameters to implement Freezable 和NameValidationParameters实现Freezable
public class NameValidationParameters : Freezable
{
public ListView OriginalTree
{
get { return (ListView)this.GetValue(OriginalTreeProperty); }
set { this.SetValue(OriginalTreeProperty, value); }
}
public string OriginalName
{
get { return (string)this.GetValue(OriginalNameProperty); }
set { this.SetValue(OriginalNameProperty, value); }
}
public static readonly DependencyProperty OriginalTreeProperty
= DependencyProperty.Register(nameof(OriginalTree), typeof(ListView),
typeof(NameValidationParameters));
public static readonly DependencyProperty OriginalNameProperty
= DependencyProperty.Register(nameof(OriginalName), typeof(object),
typeof(NameValidationParameters));
protected override Freezable CreateInstanceCore()
{
return new NameValidationParameters();
}
}
However, Here is an example of how i implemented INotifyDataErrorInfo in my project. 但是,这是我如何在项目中实现INotifyDataErrorInfo的示例。 This is a very clean way to trigger validation errors and xaml allows you to configure the display of errors
这是触发验证错误的非常干净的方法,而xaml允许您配置错误的显示
Model class: 型号类别:
public class AttributionInput
{
[Required]
public DateTime? StartDate { get; set; }
[Required]
public DateTime? EndDate { get; set; }
}
ModelWrapper Generic: 通用ModelWrapper:
public class ModelWrapper<T> : NotifyDataErrorInfoBase
{
public T Model { get; protected set; }
public ModelWrapper(T model)
{
Model = model;
}
public ModelWrapper()
{
}
protected virtual TValue GetValue<TValue>([CallerMemberName] string propertyName = null)
{
return (TValue)typeof(T).GetProperty(propertyName)?.GetValue(Model);
}
protected virtual void SetValue<TValue>(TValue value, [CallerMemberName] string propertyName = null)
{
typeof(T).GetProperty(propertyName)?.SetValue(Model, value);
OnPropertyChanged(propertyName);
ValidatePropertyInternal(propertyName, value);
}
private void ValidatePropertyInternal(string propertyName, object currentValue)
{
ClearErrors(propertyName);
ValidateDataAnnotations(propertyName, currentValue);
ValidateCustomErrors(propertyName);
}
protected virtual IEnumerable<string> ValidateProperty(string propertyName)
{
return null;
}
private void ValidateCustomErrors(string propertyName)
{
var errors = ValidateProperty(propertyName);
if (errors != null)
{
foreach (var error in errors)
{
AddError(propertyName, error);
}
}
}
private void ValidateDataAnnotations(string propertyName, object currentValue)
{
var results = new List<ValidationResult>();
var context = new ValidationContext(Model) { MemberName = propertyName };
Validator.TryValidateProperty(currentValue, context, results);
foreach (var result in results)
{
AddError(propertyName, result.ErrorMessage);
}
}
}
Generic Implementation: 通用实现:
public class AttributionInputWrapper : ModelWrapper<AttributionInput>
{
public AttributionInputWrapper(AttributionInput model) : base(model)
{
}
public DateTime? StartDate
{
get => GetValue<DateTime?>();
set
{
SetValue(value);
if (EndDate < StartDate) EndDate = StartDate;
}
}
public DateTime? EndDate
{
get => GetValue<DateTime?>();
set
{
SetValue(value);
if (EndDate < StartDate) StartDate = EndDate;
}
}
protected override IEnumerable<string> ValidateProperty(string propertyName)
{
if (propertyName == nameof(EndDate) || propertyName == nameof(StartDate))
{
//if (StartDate.Value.Date > EndDate.Value.Date) yield return "Start Date must be <= End Date";
if (EndDate != null && (EndDate.Value.DayOfWeek == DayOfWeek.Saturday || EndDate.Value.DayOfWeek == DayOfWeek.Sunday))
yield return "Please select a week day";
if (StartDate != null && (StartDate.Value.DayOfWeek == DayOfWeek.Saturday || StartDate.Value.DayOfWeek == DayOfWeek.Sunday))
yield return "Please select a week day";
}
}
}
ViewModel: ViewModel:
public class QueryViewModel : DetailViewModelBase, ICommonViewModel
{
private AttributionInputWrapper _attributionInput;
public AttributionInputWrapper AttributionInput
{
get => _attributionInput;
set
{
_attributionInput = value;
OnPropertyChanged();
}
}
}
View : 查看:
<Style TargetType="DatePicker">
<Setter Property="Margin" Value="{StaticResource MarginString}"/>
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<StackPanel>
<AdornedElementPlaceholder x:Name="Placeholder1"/>
<TextBlock Text="{Binding ElementName=Placeholder1, Path=AdornedElement.(Validation.Errors)[0].ErrorContent}" FontSize="9"/>
</StackPanel>
</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>
<DatePicker x:Name="StartDateBox" SelectedDate="{Binding AttributionInput.StartDate, UpdateSourceTrigger=PropertyChanged}" DisplayDateStart="10/01/2017" DisplayDateEnd="{x:Static system:DateTime.Now}"/>
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.