Für MVVM bevorzuge ich Attached Properties für diese Art von Sache, weil sie wiederverwendbar sind und es hält die Ansicht Modelle sauber.
Um die Validation.HasError-Eigenschaft an Ihr Ansichtsmodell zu binden, müssen Sie eine angefügte Eigenschaft erstellen, die über CoerceValueCallback den Wert der angefügten Eigenschaft mit der Validation.HasError-Eigenschaft des Steuerelements, das Sie validieren, synchronisiert Eingabe an.
This Artikel erläutert, wie diese Technik verwendet wird, um das Problem zu beheben, das Ansichtsmodell von WPF ValidationRule-Fehlern zu melden. Der Code war in VB, also portierte ich ihn auf C#, wenn Sie keine VB-Person sind.
Die angefügte Eigenschaft
public static class ValidationBehavior
{
#region Attached Properties
public static readonly DependencyProperty HasErrorProperty = DependencyProperty.RegisterAttached(
"HasError",
typeof(bool),
typeof(ValidationBehavior),
new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null, CoerceHasError));
private static readonly DependencyProperty HasErrorDescriptorProperty = DependencyProperty.RegisterAttached(
"HasErrorDescriptor",
typeof(DependencyPropertyDescriptor),
typeof(ValidationBehavior));
#endregion
private static DependencyPropertyDescriptor GetHasErrorDescriptor(DependencyObject d)
{
return (DependencyPropertyDescriptor)d.GetValue(HasErrorDescriptorProperty);
}
private static void SetHasErrorDescriptor(DependencyObject d, DependencyPropertyDescriptor value)
{
d.SetValue(HasErrorDescriptorProperty, value);
}
#region Attached Property Getters and setters
public static bool GetHasError(DependencyObject d)
{
return (bool)d.GetValue(HasErrorProperty);
}
public static void SetHasError(DependencyObject d, bool value)
{
d.SetValue(HasErrorProperty, value);
}
#endregion
#region CallBacks
private static object CoerceHasError(DependencyObject d, object baseValue)
{
var result = (bool)baseValue;
if (BindingOperations.IsDataBound(d, HasErrorProperty))
{
if (GetHasErrorDescriptor(d) == null)
{
var desc = DependencyPropertyDescriptor.FromProperty(System.Windows.Controls.Validation.HasErrorProperty, d.GetType());
desc.AddValueChanged(d, OnHasErrorChanged);
SetHasErrorDescriptor(d, desc);
result = System.Windows.Controls.Validation.GetHasError(d);
}
}
else
{
if (GetHasErrorDescriptor(d) != null)
{
var desc = GetHasErrorDescriptor(d);
desc.RemoveValueChanged(d, OnHasErrorChanged);
SetHasErrorDescriptor(d, null);
}
}
return result;
}
private static void OnHasErrorChanged(object sender, EventArgs e)
{
var d = sender as DependencyObject;
if (d != null)
{
d.SetValue(HasErrorProperty, d.GetValue(System.Windows.Controls.Validation.HasErrorProperty));
}
}
#endregion
}
mit dem beiliegenden Eigentum in XAML
<Window
x:Class="MySolution.MyProject.MainWindow"
xmlns:v="clr-namespace:MyNamespace;assembly=MyAssembly">
<TextBox
v:ValidationBehavior.HasError="{Binding MyPropertyOnMyViewModel}">
<TextBox.Text>
<Binding
Path="ValidationText"
UpdateSourceTrigger="PropertyChanged">
<Binding.ValidationRules>
<v:SomeValidationRuleInMyNamespace/>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
</ Window >
Nun ist die Eigenschaft auf Ihrer Ansicht Modell wird mit Validation.HasError auf Textbox synchronisiert werden.
Alex, Danke für Ihre Antwort. Ich verwende den von Ihnen vorgeschlagenen zweiten Weg. Obwohl diese Vorgehensweise für das aktuelle Problem ausreichend ist, suchte ich nach einer generischen Lösung für die Verwendung von ValidationRule in Kombination mit IDateErrorInfo. Ich stieß auf ein Problem während der Lösung und wird hier veröffentlicht (http://stackoverflow.com/questions/10629278/strange-order-of-firing-of-validation-error-event-added-fired-before-removed). Ich wäre sehr dankbar für Ihren Rat in dieser Frage. Da mein aktuelles Problem gelöst ist, werde ich Ihre Antwort als richtig markieren. Prost. Nirvan – Jatin
Ich würde dringend davon abraten, Validierungsregeln zu verwenden. Sie sind auf der Bindungsebene und wurden entwickelt, um in Code hinter verwendet zu werden, und sind nicht gut für MVVM geeignet. Möglicherweise können Sie sie zur Zusammenarbeit bringen, aber dazu müssten Sie Ihr ViewModel mit der Ansicht verbinden und durch die logische Baumprüfung von Bindungen navigieren und diese an ViewModel binden. Ich schaudere, wenn ich daran denke. Schau dir das an: http://stackoverflow.com/questions/63646/wpf-data-binding-and-validation-rules-best-practices –
Für mich würde ich immer versuchen, dem Pfad des geringsten Widerstands zu folgen, und Verwenden Sie einfach ein Steuerelement, das keine ungültigen Eingaben enthält, die nicht zum ViewModel gelangen. Ich möchte, dass sich der gesamte Validierungscode in ViewModel befindet, also an einem Ort und unter meiner Kontrolle. –