Cholera, zajęło mi to trochę czasu, ale jak zwykle ... przywiązane zachowania na ratunek.
To, na co patrzysz, to brudne śledzenie stanu. Można to zrobić na wiele sposobów za pomocą narzędzia ViewModel, ale ponieważ nie chcesz zmieniać swoich jednostek, najlepszym sposobem jest stosowanie zachowań.
Po pierwsze usuń ValidatesOnDataErrors z powiązania Xaml. Utwórz zachowanie dla formantu, nad którym pracujesz (jak pokazano poniżej dla TextBox
) iw zdarzeniu (lub dowolnie wybranym zdarzeniu) zresetuj powiązanie z tym, które jest sprawdzane pod kątem błędów danych. Proste naprawdę.
W ten sposób twoje jednostki nie muszą się zmieniać, twój Xaml jest utrzymywany w rozsądnej czystości i dostajesz swoje zachowanie.
Oto zachowanie 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);
};
}
}
}
I XAML jest dość prosta zbyt.
<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.
Oddajemy nagrodę za to pytanie w nadziei na niehackowe rozwiązanie, jeśli takie istnieje. –
Nie możesz po prostu utworzyć osoby przed wywołaniem funkcji InitializeComponent()? – markmnl
Dodano nagrodę, aby uzyskać dobre, niegroźne rozwiązanie. –