我意识到.NET Framework 4.5中出现了这个界面
我首先想看看如何在Silverlight中实现(我可以想象它以相同的方式实现),但我找不到这个新界面的紧凑演示.是否可以显示我如何使用它?
我真的想找一个小的演示来理解它
这是一个奇怪的,在这一点上,我认为它可能与我的机器配置有关.
基本上我已经创建了一个非常标准的实现,INotifyDataErrorInfo在某些情况下,当ErrorsChanged我提出一个事件时ArgumentOutOfRangeException.此异常不包含太多信息; 它给了我ArgumentOutOfRangeException crossed a native/managed boundary加上ArgumentOutOfRangeException关于非负索引和集合大小的标准描述.该InnerException为空.堆栈跟踪如下:
at System.ThrowHelper
.ThrowArgumentOutOfRangeException(ExceptionArgument argument,
ExceptionResource resource)
at System.ThrowHelper.ThrowArgumentOutOfRangeException()
at System.Collections.Generic.List`1.get_Item(Int32 index)
at System.Collections.ObjectModel.Collection`1.get_Item(Int32 index)
at System.Collections.ObjectModel.ReadOnlyCollection`1.get_Item(Int32 index)
Run Code Online (Sandbox Code Playgroud)
我提到我的机器配置的原因是因为我尝试了一些发布到博客的解决方案(例如这里和这里)并得到相同的问题(即不是我的代码,INotifyDataErrorInfo的另一个实现)并且在评论中没有提及任何其他人我遇到的问题.谷歌搜索出现了几个随机点击,没有帮助.
所需的州如下:
更新:如果我将焦点从显示验证错误的TextBox移开,我也可以重现.
我有点想知道我是否错过了服务包/更新或者某些东西,因为从我看到它看起来好像框架代码中的一个非常基本的错误,同时它没有发生在其他人身上.
更新:我正在使用Silverlight 4的最终RTM版本.不是RC或Beta.
更新:我得到与本白皮书提供的官方MS样本相同的结果.
更新:我现在已经在另一台机器上测试了我的代码和提到的样本,它运行正常.我仍然真的想解决这个问题,因为它有点令人不安,因为它不适用于我的常规机器(直到现在我都没有遇到任何麻烦).关于如何追踪导致这种情况的任何建议将不胜感激.我已经在问题机器上重新安装了Silverlight(Runtime,SDK,Toolkit),但这还没有解决问题.
更新:这是框架代码的调用堆栈,其中通过启用MS服务器的源服务器支持获得异常:
mscorlib.dll!System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument argument, System.ExceptionResource resource) + 0x40 bytes
mscorlib.dll!System.ThrowHelper.ThrowArgumentOutOfRangeException() + 0x10 bytes
mscorlib.dll!System.Collections.Generic.List<System.Windows.Controls.ValidationError>.this[int].get(int index = 0) + 0x13 bytes
mscorlib.dll!System.Collections.ObjectModel.Collection<System.Windows.Controls.ValidationError>.this[int].get(int index) + 0x2e …Run Code Online (Sandbox Code Playgroud) 我在 WPF 中使用 INotifyDataError 接口进行异步验证。我有房产
<TextBox Grid.Column="5"
Text="{Binding XXX.Name, ValidatesOnNotifyDataErrors=True}"/>
Run Code Online (Sandbox Code Playgroud)
在我的视图模型上,我有一个属性
public SomeType XXX
Run Code Online (Sandbox Code Playgroud)
并且在 SomeType 类型上我有属性
public string Name
Run Code Online (Sandbox Code Playgroud)
现在我的 ViewModel 实现了 INotifyPropertyChanged 和 INotifyDataError 并且验证是在我的 viewmodel 类中异步完成的。SomeType 仅实现 INotifyPropertyChanged。
我的问题是这个。当我ErrorsChanged用DataErrorsChangedEventArgs(propertyName))propertyName 应该是什么引发事件时。注意我的绑定路径是XXX.Name. 应该 propertyName 是
或者别的什么,或者我必须在我的SomeType类中实现 INotifyDataErrorInfo以及我希望不必这样做,因为我希望我的验证留在主视图模型中。
无论如何,我已经尝试了上述两种方法,尽管我可以验证是否引发了错误事件,但文本框周围没有出现红色框。
我有多个控件,包括TextBox和ComboBox,我希望所有控件都显示一个ToolTip,其中包含Validation.Errors集合中包含的所有错误.如果可能的话,我希望他们都能分享一种共同的风格,这就是我的努力.我确信我在ToolTip setter中的绑定有问题,但我无法弄清楚是什么.我在INotifyDataErrorInfo实现中返回一个Error对象,该对象指定错误的严重性(错误或警告).
我希望有一个适用于Window中所有控件的样式,它将显示一个ToolTip,其中包含该控件的所有错误和警告的列表.错误应显示为红色,警告显示为黄色.这是我提出的风格:
<Style TargetType="FrameworkElement">
<Setter Property="ToolTip">
<Setter.Value>
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors), RelativeSource={RelativeSource Self}}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent.ErrorMessage}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
Value="{x:Static local:ErrorType.Warning}">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=(Validation.HasError)}" Value="True">
<Setter Property="ToolTip">
<Setter.Value>
<ItemsControl ItemsSource="{Binding Path=(Validation.Errors)}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ErrorContent.ErrorMessage}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding ErrorContent.ErrorSeverity}"
Value="{x:Static local:ErrorType.Warning}">
<Setter Property="Foreground" Value="Yellow"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</DataTemplate> …Run Code Online (Sandbox Code Playgroud) 直到最近,我还使用了IDataErrorInfo接口的自定义扩展版本。我的扩展程序使我可以同时处理多个错误,到目前为止,它为我提供了很好的服务。但是,随着INotifyDataErrorInfo界面的引入,我想我将对其进行试验以查看是否有任何改进。
在阅读了一些在线教程之后,我从中获得了它与各种ValidationAttributes的配合使用System.ComponentModel.DataAnnotations namespace。使用这些,Attribute您可以提供如下基本验证规则:
[MinLength(3, ErrorMessage = "Name must be longer than 3 characters.")]
public string Name
{
get { return name; }
set { name = value; NotifyPropertyChanged("Name"); Validate("Name", name); }
}
Run Code Online (Sandbox Code Playgroud)
最初,它看起来还不错,因为错误消息直接插入Valaidation.Errors了Applied ErrorTemplates中可用的集合中。但是,大多数内置的验证规则实际上都是最基本的,我已经习惯于实现涉及其他属性值的复杂验证规则。
因此,我着手寻找一种创建包含多个属性的简单验证规则的方法:必须设置两个或多个字段之一的规则。因此,我声明了一个扩展的类,ValidationAttribute并在在线搜索后找到了一种访问其他属性值的方法。
我敲了一个基本UI,并ErrorTemplate在每个UI上应用了一个自定义TextBox,它显示Validation.Errors了数据绑定属性的集合:
<ControlTemplate x:Key="ErrorTemplate">
<StackPanel Orientation="Horizontal">
<Border BorderBrush="#4FFF0000" BorderThickness="1" Margin="0,10">
<AdornedElementPlaceholder />
</Border>
<Image Name="WarningImage" Source="pack://application:,,,/WpfApplication1;component/Images/Warning_16.png" Margin="5,0,0,0" Tag="{Binding}" />
<Popup PlacementTarget="{Binding ElementName=WarningImage}" Placement="Right" Margin="5,0,0,0" AllowsTransparency="True" …Run Code Online (Sandbox Code Playgroud) INotifyDataErrorInfo 内部只有 3 个内容:
\n\nHasErrors:一个只读布尔属性,用于判断对象作为一个整体是否存在任何验证错误;
\n GetErrors:返回给定属性的验证错误的方法;
\nErrorsChanged:当检测到新错误 \xe2\x80\x93 或缺少错误 \xe2\x80\x93 时必须引发的事件。您必须为每个属性引发此事件。
在演示项目中,我创建了一个表单,它显示名为 的对象的属性\xe2\x80\x98Person\xe2\x80\x99。以下是如何在绑定中启用 INotifyDataErrorInfo 验证:
<TextBox Text="{Binding Name,Mode=TwoWay,ValidatesOnNotifyDataErrors=True}"/>\nRun Code Online (Sandbox Code Playgroud)\n\n我们必须将该ValidatesOnNotifyDataErrors属性设置为true。
然后,绑定将自行注册绑定的 Person 的 ErrorsChanged 事件。每次为绑定属性引发此事件时,控件都会自行调整以显示错误。仅当 HasErrors 设置为 true 时才会执行此操作。
\n\n问题:
\n\nErrorsChanged event is raised for\n the binded property, the controls will dress itself to display an\n error?如果我绑定Address.Country,Person是否会为ErrorsChanged绑定的属性引发事件?Address.Country为什么?有没有办法让这个绑定也显示错误?
在WPF中,有3种验证方法:
IDataErrorInfoINotifyDataErrorInfo是否可以同时使用它们的组合?对于我的需求,我想使用INotifyDataErrorInfo的灵活性来验证新规则,但是不想干扰要验证的同一对象的现有ValidationRules。
所以我有一个像这个简化版本的控件:
<local:ImageMapField x:Class="ImageApp.WPF.Controls.ImageMapContentField"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ImageApp.WPF.Controls"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
x:Name="Me">
<Grid HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" HorizontalAlignment="Stretch" Style="{DynamicResource BaseLabelStyle}">
<TextBlock Text="{Binding Header, RelativeSource={RelativeSource AncestorType=local:ImageMapContentField, Mode=FindAncestor}}" TextWrapping="WrapWithOverflow"></TextBlock>
</Label>
<StackPanel Grid.Column="1">
<Image />
<Border Margin="20,5,5,2">
<ContentPresenter Content="{Binding DataEntryContent, ElementName=Me}" />
</Border>
</StackPanel>
</Grid>
</local:ImageMapField>
Run Code Online (Sandbox Code Playgroud)
我像这样使用它:
<controls:ImageMapContentField Header="Foo Date"
FieldName="FooDate"
ImageSource="{Binding MyImage, Mode=TwoWay}"
ItemsSource="{Binding Map.Items}"
Zoom="{Binding MapFieldZoom}">
<controls:ImageMapContentField.DataEntryContent>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Text="{Binding MyDate, StringFormat=MM/dd/yyyy, ValidatesOnDataErrors=True, NotifyOnValidationError=True}">
<controls:WatermarkService.Watermark>
<TextBlock>Date</TextBlock>
</controls:WatermarkService.Watermark> …Run Code Online (Sandbox Code Playgroud) 我在WPF 4.5项目中做了一个简单的INotifyDataErrorInfo实现.这是WPF的新界面,但已在Silverlight中使用了一段时间.
我知道NET4.5仍然被认为是alpha,但我正在尝试解决它是我的代码还是错误的框架.
接口按预期工作,但是当对象绑定到DataGrid时失败.
我收到的例外是:
用户代码未处理System.NullReferenceException
消息=未将对象引用设置为对象的实例.
源= PresentationFramework堆栈跟踪:在MS.Internal.Data.ClrBindingWorker.OnDataErrorsChanged(INotifyDataErrorInfo indei,字符串PROPNAME)在MS.Internal.Data.PropertyPathWorker.OnErrorsChanged(对象发件人,DataErrorsChangedEventArgs e)上System.Windows.WeakEventManager.ListenerList`1.位于System.ComponentModel.ErrorsChangedEventManager.OnErrorsChanged(Object sender,DataErrorsChangedEventArgs args)的System.Windows.WeakEventManager.DeliverEvent(Object sender,EventArgs args)中的DeliverEvent(Object sender,EventArgs e,Type managerType)INotifyDataErrorInfoTest.Person.NotifyErrorsChanged(String property) )在INotifyDataErrorInfoTest\Person.cs:线109在INotifyDataErrorInfoTest.Person.AddErrorForProperty(String属性,字符串误差)INotifyDataErrorInfoTest\Person.cs:管线122 INotifyDataErrorInfoTest.Person.Validate(字符串propertyName的)在INotifyDataErrorInfoTest\Person.cs:线INotifyDataErrorInfoTest中的INotifyDataErrorInfoTest.Person.set_FirstName(String value)中的150\Person.cs:第18行
代码位于http://dl.dropbox.com/u/14740106/INotifyDataErrorInfoTest.zip下方或项目中
如果共识是这是一个错误,那么我将发布到MS Connect.
测试:有两个文本框绑定到Person对象的单个实例.将第一个文本框设置为具有值的James,它将无法通过验证并显示红色框.如果将网格中任何用户的名字设置为James,则会抛出异常.
PS:我知道它不是MVVM,但它只是为了证明或反驳问题.
public class Person : INotifyDataErrorInfo, INotifyPropertyChanged
{
string _firstName;
public string FirstName
{
get { return _firstName; }
set
{
_firstName = value;
Validate("FirstName");
OnPropertyChanged("FirstName");
}
}
string _lastName;
public string LastName
{
get { return _lastName; }
set
{
_lastName = value;
Validate("LastName");
OnPropertyChanged("LastName");
}
}
public Person()
{
} …Run Code Online (Sandbox Code Playgroud) 我有一个模型实现两者INotifyPropertyChanged和INotifyDataErrorInfo.当我修改了属性时,属性更改了事件触发,但由于某种原因,当我引发Error事件处理程序时,UI会调用GetErrors方法.这导致验证错误未呈现给UI.
有人可以看看我如何设置INotifyDataErrorInfo并告诉我我是否做错了什么?
基础模型实施
public class BaseChangeNotify : INotifyPropertyChanged, INotifyDataErrorInfo
{
private bool isDirty;
private Dictionary<string, List<string>> errors = new Dictionary<string, List<string>>();
public BaseChangeNotify()
{
}
public event PropertyChangedEventHandler PropertyChanged;
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public bool IsDirty
{
get
{
return this.isDirty;
}
set
{
this.isDirty = value;
this.OnPropertyChanged();
}
}
public bool HasErrors
{
get
{
return this.errors.Count(e => e.GetType() == typeof(ErrorMessage)) > 0;
}
}
public IEnumerable GetErrors(string propertyName)
{
if (string.IsNullOrEmpty(propertyName) ||
!this.errors.ContainsKey(propertyName))
{ …Run Code Online (Sandbox Code Playgroud) 当 TextBox 为空时,我有一个简单的验证来显示错误消息。问题在于消息只显示消息的第一个字母。
在文本框样式中:
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="{Binding Path=(Validation.Errors)[0].ErrorContent, RelativeSource={x:Static RelativeSource.Self}}" />
</Trigger>
Run Code Online (Sandbox Code Playgroud)
如果我将错误消息直接设置为 Setter 值,它会毫无问题地显示所有内容。
<Trigger Property="Validation.HasError" Value="True">
<Setter Property="ToolTip" Value="This field is required!" />
</Trigger>
Run Code Online (Sandbox Code Playgroud)
XAML 代码:
<TextBox Text="{Binding Name, Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged,
ValidatesOnNotifyDataErrors=True,
NotifyOnValidationError=True}" />
Run Code Online (Sandbox Code Playgroud)
C# 代码
private readonly Dictionary<string, string> _errors = new Dictionary<string, string>();
private readonly object _lock = new object();
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
string errorsForName;
lock (_lock)
{
errorsForName = _errors.FirstOrDefault(e => e.Key == propertyName).Value;//.TryGetValue(propertyName, …Run Code Online (Sandbox Code Playgroud) 我有一个 ObservableCollection 类型的数据集合(比如 myClassTypes 实例)。在一些用户操作之后,这个 myClassTypes 填充了 ViewModel 中的值。在视图中,有一个文本框,用户可以在其中输入文本。我需要根据 myClassTypes 值验证文本框数据。因此,如果 myClassTypes 包含用户在文本框中插入的文本,则验证通过,否则将失败。我的代码片段是:ViewModel:
public ObservableCollection < MyClassType > ViewModelClassTypes {
get {
return _myClassTypes;
}
set {
_myClassTypes = value;
NotifyOfPropertyChange(() = >MyClassTypes);
}
}
public class TestValidationRule: ValidationRule {
public ObservableCollection < MyClassType > MyClassTypes {
get = >(ObservableCollection < MyClassType > ) GetValue(MyClassTypesProperty);
set = >SetValue(MyClassTypesProperty, value);
}
}
Run Code Online (Sandbox Code Playgroud)
仅供参考:MyClassTypesProperty 是一个依赖属性
我的 View.xaml 是:
<TextBox>
<TextBox.Text>
<Binding UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<validationRules:TestValidationRule MyClassTypes="{Binding ViewModelClassTypes}"/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
Run Code Online (Sandbox Code Playgroud)
我无法在 MyClassTypes …
我有一个TextBlock和一个CheckBox,例如:
<StackPanel >
<TextBlock Text="Colors"/>
<CheckBox Content="Blue" IsChecked="{Binding Model.Blue, ValidatesOnNotifyDataErrors=False}"/>
</StackPanel>
Run Code Online (Sandbox Code Playgroud)
在我的模型中,我正在实现INotifyDataErrorInfo并验证是否选中了该复选框。如果未检查,则将其视为错误:
public class MyModel : INotifyPropertyChanged, INotifyDataErrorInfo
{
[CustomValidation(typeof(MyModel), "CheckBoxRequired")]
public bool Blue
{
get { return _blue; }
set { _blue = value; RaisePropertyChanged(nameof(Blue)); }
}
public static ValidationResult CheckBoxRequired(object obj, ValidationContext context)
{
var model = (MyModel)context.ObjectInstance;
if (model.Blue == false)
return new ValidationResult("Blue required", new string[] { "Blue" });
else
return ValidationResult.Success;
}
//...
//INotifyPropertyChanged & INotifyDataErrorInfo implementations omitted
} …Run Code Online (Sandbox Code Playgroud) wpf ×12
c# ×9
validation ×7
mvvm ×3
.net-4.5 ×2
silverlight ×2
xaml ×2
binding ×1
data-binding ×1
viewmodel ×1
wpf-style ×1