TextBox の最初の LostFocus で WPF 検証が起動しない
-
01-07-2019 - |
質問
オブジェクトに対して WPF フォームを検証しようとしています。テキストボックスに何かを入力すると、検証が開始され、フォーカスが失われ、テキストボックスに戻って、書き込んだ内容が消去されます。しかし、WPF アプリケーションをロードし、テキスト ボックスに何も書き込んだり削除したりせずに、テキスト ボックスをタブで移動するだけでは、アプリケーションは起動されません。
Customer.cs クラスは次のとおりです。
public class Customer : IDataErrorInfo
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string Error
{
get { throw new NotImplementedException(); }
}
public string this[string columnName]
{
get
{
string result = null;
if (columnName.Equals("FirstName"))
{
if (String.IsNullOrEmpty(FirstName))
{
result = "FirstName cannot be null or empty";
}
}
else if (columnName.Equals("LastName"))
{
if (String.IsNullOrEmpty(LastName))
{
result = "LastName cannot be null or empty";
}
}
return result;
}
}
}
そして、これが WPF コードです。
<TextBlock Grid.Row="1" Margin="10" Grid.Column="0">LastName</TextBlock>
<TextBox Style="{StaticResource textBoxStyle}" Name="txtLastName" Margin="10"
VerticalAlignment="Top" Grid.Row="1" Grid.Column="1">
<Binding Source="{StaticResource CustomerKey}" Path="LastName"
ValidatesOnExceptions="True" ValidatesOnDataErrors="True"
UpdateSourceTrigger="LostFocus"/>
</TextBox>
解決
コードの背後にロジックを少し追加することに抵抗がない場合は、実際のコードを処理できます。 ロストフォーカス 次のようなイベント:
.xaml
<TextBox LostFocus="TextBox_LostFocus" ....
.xaml.cs
private void TextBox_LostFocus(object sender, RoutedEventArgs e)
{
((Control)sender).GetBindingExpression(TextBox.TextProperty).UpdateSource();
}
他のヒント
残念ながら、これは仕様によるものです。WPF 検証は、コントロールの値が変更された場合にのみ実行されます。
信じられないことですが、本当です。これまでのところ、WPF の検証は大きな苦痛であり、ひどいものです。
ただし、できることの 1 つは、コントロールのプロパティからバインディング式を取得し、手動で検証を呼び出すことです。最悪ですが、うまくいきます。
を見てください。 ValidatesOnTargetUpdated ValidationRule のプロパティ。データが最初にロードされるときに検証されます。これは、空のフィールドまたは null フィールドをキャッチしようとしている場合に適しています。
バインディング要素を次のように更新します。
<Binding
Source="{StaticResource CustomerKey}"
Path="LastName"
ValidatesOnExceptions="True"
ValidatesOnDataErrors="True"
UpdateSourceTrigger="LostFocus">
<Binding.ValidationRules>
<DataErrorValidationRule
ValidatesOnTargetUpdated="True" />
</Binding.ValidationRules>
</Binding>
これを処理する最良の方法は、テキストボックスのLostFocusイベントで行うことであることがわかりました。次のようなことを行います
private void dbaseNameTextBox_LostFocus(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(dbaseNameTextBox.Text))
{
dbaseNameTextBox.Text = string.Empty;
}
}
その後、エラーが表示されます
私は同じ問題を経験し、これを解決する非常に簡単な方法を見つけました。ウィンドウの Loaded イベントに、txtLastName.Text = String.Empty と入力するだけです。それでおしまい!!オブジェクトのプロパティが変更された (空の文字列に設定された) ため、検証が開始されます。
次のコードは、すべてのコントロールをループして検証します。必ずしも好ましい方法ではありませんが、うまくいくようです。TextBlocks と TextBoxes のみを実行しますが、簡単に変更できます。
public static class PreValidation
{
public static IEnumerable<T> FindVisualChildren<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj != null)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
if (child != null && child is T)
{
yield return (T)child;
}
foreach (T childOfChild in FindVisualChildren<T>(child))
{
yield return childOfChild;
}
}
}
}
public static void Validate(DependencyObject depObj)
{
foreach(var c in FindVisualChildren<FrameworkElement>(depObj))
{
DependencyProperty p = null;
if (c is TextBlock)
p = TextBlock.TextProperty;
else if (c is TextBox)
p = TextBox.TextProperty;
if (p != null && c.GetBindingExpression(p) != null) c.GetBindingExpression(p).UpdateSource();
}
}
}
ウィンドウまたはコントロールで Validate を呼び出すだけで、事前に検証されます。