Verdammt das hat eine Weile gedauert, aber wie immer, ... beigefügt Verhalten zur Rettung.
Was Sie im Wesentlichen betrachten, ist die Verfolgung des schmutzigen Zustandes. Es gibt viele Möglichkeiten, dies mit Ihrem ViewModel zu tun, aber da Sie Ihre Entitäten nicht ändern wollten, verwenden Sie am besten das Verhalten.
Zuerst entfernen Sie die ValidatesOnDataErrors aus Ihrer Xaml-Bindung. Erstellen Sie ein Verhalten für das Steuerelement, an dem Sie gerade arbeiten (wie unten für TextBox
gezeigt) und im Ereignis TextChanged
(oder einem anderen gewünschten Ereignis) setzen Sie die Bindung auf setzt auf Datenfehler zurück. Einfach wirklich.
Auf diese Weise müssen sich Ihre Entitäten nicht ändern, Ihr Xaml wird einigermaßen sauber gehalten und Sie erhalten Ihr Verhalten.
Hier ist das Verhalten Code-
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace IDataErrorInfoSample
{
public static class DirtyStateBehaviours
{
public static string GetDirtyBindingProperty(DependencyObject obj)
{
return (string)obj.GetValue(DirtyBindingPropertyProperty);
}
public static void SetDirtyBindingProperty(DependencyObject obj, string value)
{
obj.SetValue(DirtyBindingPropertyProperty, value);
}
// Using a DependencyProperty as the backing store for DirtyBindingProperty. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DirtyBindingPropertyProperty =
DependencyProperty.RegisterAttached("DirtyBindingProperty", typeof(string), typeof(DirtyStateBehaviours),
new PropertyMetadata(new PropertyChangedCallback(Callback)));
public static void Callback(DependencyObject obj,
DependencyPropertyChangedEventArgs args)
{
var textbox = obj as TextBox;
textbox.TextChanged += (o, s) =>
{
Binding b = new Binding(GetDirtyBindingProperty(textbox));
b.ValidatesOnDataErrors = true;
textbox.SetBinding(TextBox.TextProperty, b);
};
}
}
}
Und die XAML ist ziemlich gerade zu nach vorne.
<Window x:Class="IDataErrorInfoSample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:IDataErrorInfoSample"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
Title="MainWindow"
Height="350"
Width="525">
<Window.DataContext>
<local:Person />
</Window.DataContext>
<StackPanel Margin="20">
<TextBox Height="20"
Margin="0,0,0,10"
local:DirtyStateBehaviours.DirtyBindingProperty="Name"
Text="{Binding Path=Name}">
</TextBox>
<Button Content="Go" />
</StackPanel>
HTH, Stimul8d.
Ich gebe ein Kopfgeld auf diese Frage in der Hoffnung auf eine nicht-hacky Lösung, wenn eine existiert. –
Können Sie nicht einfach die Person erstellen, bevor InitializeComponent() aufgerufen wird? – markmnl
Hinzugefügt Bounty, um eine gute nicht-hacky Lösung zu bekommen .. –