以下に示すように、IDataErrorInfoインターフェイスとスタイルを使用してWPFでテキストボックスを検証する標準的な方法と思われる方法を採用しました。ただし、ページが無効になったときに[保存]ボタンを無効にするにはどうすればよいですか?これはどういうわけかトリガーを介して行われますか?
Default Public ReadOnly Property Item(ByVal propertyName As String) As String Implements IDataErrorInfo.Item
Get
Dim valid As Boolean = True
If propertyName = "IncidentCategory" Then
valid = True
If Len(IncidentCategory) = 0 Then
valid = False
End If
If Not valid Then
Return "Incident category is required"
End If
End If
Return Nothing
End Get
End Property
<Style TargetType="{x:Type TextBox}">
<Setter Property="Margin" Value="3" />
<Setter Property="Height" Value="23" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="MyAdorner" />
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors)[0].ErrorContent}" />
</Trigger>
</Style.Triggers>
</Style>
いくつかのこと:
まず、保存ボタンの処理を実装するには、RoutedCommand _ApplicationCommands.Save
_を使用することをお勧めします。
WPFコマンドモデルをまだチェックアウトしていない場合は、スクープを取得できます ここ 。
_<Button Content="Save" Command="Save">
_
ここで、機能を実装するために、Window/UserControlまたはボタン自体にコマンドバインディングを追加できます。
_ <Button.CommandBindings>
<CommandBinding Command="Save"
Executed="Save_Executed" CanExecute="Save_CanExecute"/>
</Button.CommandBindings>
</Button>
_
これらをコードビハインドで実装します。
_private void Save_Executed(object sender, ExecutedRoutedEventArgs e)
{
}
private void Save_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
}
_
_Save_CanExecute
_で、テキストボックスのバインディングの有効性に基づいて_e.CanExecute
_を設定します。
MVVM(Model-View-ViewModel)デザインパターンを使用して実装する場合は、 CommandSinkBinding に関するJoshSmithの投稿を確認してください。
最後に、TextBox
の値が変更されたらすぐに有効化/無効化を更新する場合は、TextBox
のバインディングに_UpdateSourceTrigger="PropertyChanged"
_を設定します。
編集:コントロール内のすべてのバインディングに基づいて検証/無効化する場合は、いくつかの提案があります。
1)すでにIDataErrorInfo
を実装しています。 _IDataErrorInfo.Error
_プロパティを実装して、バインドしているすべてのプロパティに対して無効な文字列を返すようにしてください。これは、コントロール全体が単一のデータオブジェクトにバインドされている場合にのみ機能します。 e.CanExecute = string.IsNullOrEmpty(data.Error);
を設定します
2)リフレクションを使用して、関連するコントロールのすべてのパブリック静的DependencyPropertiesを取得します。次に、各プロパティのループでBindingOperations.GetBindingExpression(relevantControl, DependencyProperty)
を呼び出して、検証をテストできるようにします。
3)コンストラクターで、ネストされたコントロールにバインドされたすべてのプロパティのコレクションを手動で作成します。 CanExecuteで、このコレクションを反復処理し、BindingOperation.GetBindingExpression()
を使用して式を取得してから_BindingExpression.HasError
_を調べることにより、各DependencyObject
/DepencyProperty
の組み合わせを検証します。
このためだけに添付プロパティを作成しました:
public static class DataErrorInfoHelper
{
public static object GetDataErrorInfo(ButtonBase obj)
{
return (object)obj.GetValue(DataErrorInfoProperty);
}
public static void SetDataErrorInfo(ButtonBase obj, object value)
{
obj.SetValue(DataErrorInfoProperty, value);
}
// Using a DependencyProperty as the backing store for DataErrorInfo. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataErrorInfoProperty =
DependencyProperty.RegisterAttached("DataErrorInfo", typeof(object), typeof(DataErrorInfoHelper), new PropertyMetadata(null, OnDataErrorInfoChanged));
private static void OnDataErrorInfoChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var button = d as ButtonBase;
if (button.Tag == null)
button.Tag = new DataErrorInfoContext { Button = button };
var context = button.Tag as DataErrorInfoContext;
if(e.OldValue != null)
{
PropertyChangedEventManager.RemoveHandler(((INotifyPropertyChanged)e.OldValue), context.Handler, string.Empty);
}
var inotify = e.NewValue as INotifyPropertyChanged;
if (inotify != null)
{
PropertyChangedEventManager.AddHandler(inotify, context.Handler, string.Empty);
context.Handler(inotify, new PropertyChangedEventArgs(string.Empty));
}
}
private class DataErrorInfoContext
{
public ButtonBase Button { get; set; }
public void Handler(object sender, PropertyChangedEventArgs e)
{
var dei = sender as IDataErrorInfo;
foreach (var property in dei.GetType().GetProperties())
{
if (!string.IsNullOrEmpty(dei[property.Name]))
{
Button.IsEnabled = false;
return;
}
}
Button.IsEnabled = string.IsNullOrEmpty(dei.Error);
}
}
}
私は自分のフォームでこのように使用しています:
<TextBlock Margin="2">e-mail:</TextBlock>
<TextBox Margin="2" Text="{Binding Email, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>
<!-- other databindings--->
<Button Margin="2" local:DataErrorInfoHelper.DataErrorInfo="{Binding}" Commands="{Binding SaveCommand}">Create account</Button>