2009-04-16 34 views
21

IDataErrorInfoインターフェイスとスタイルを使用して、WPFでテキストボックスを検証する標準的な方法を採用しました。ただし、ページが無効になったときに[保存]ボタンを無効にするにはどうすればよいですか?これは何とかトリガーによって行われますか?検証が失敗した場合、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> 

答えて

37

物事のカップル:

まず、私は、保存ボタンのハンドリングを実現するためにRoutedCommandのApplicationCommands.Saveを使用することをお勧めします。

WPFコマンドモデルをチェックアウトしていない場合は、スクープhereを取得できます。

<Button Content="Save" Command="Save"> 

さて、機能を実装するために、あなたはウィンドウ/ユーザーコントロールにまたはボタン自体に結合するコマンドを追加することができます。

<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のJosh Smithの投稿をご覧ください。

最後に、TextBoxの値が変更されるとすぐに有効/無効を更新する場合は、TextBoxのバインディングにUpdateSourceTrigger="PropertyChanged"を設定してください。

EDIT:コントロール内のすべてのバインディングに基づいて検証/無効化を行う場合は、次の点を参考にしてください。

1)すでにIDataErrorInfoを実装しています。 IDataErrorInfo.Errorプロパティを実装して、バインディングするすべてのプロパティに対して無効な文字列を返すようにしてください。これは、コントロール全体が単一のデータオブジェクトにバインドされている場合にのみ機能します。 Set e.CanExecute = string.IsNullOrEmpty(data.Error);

2)リフレクションを使用して、関連するコントロールのすべてのパブリック静的DependencyPropertiesを取得します。次に、各プロパティのループでBindingOperations.GetBindingExpression(relevantControl, DependencyProperty)を呼び出して、検証をテストすることができます。

3)コンストラクタで、ネストされたコントロールのすべてのバインドされたプロパティのコレクションを手動で作成します。 CanExecuteでこのコレクションを繰り返し、を使用して式を取得し、BindingExpression.HasErrorを調べて、各DependencyObject/DepencyPropertyの組み合わせを検証します。

+1

は非常に多くのおかげで動作します。しかしもう一つのこと。偽その後Validation.GetHasError(MyTextBoxを)e.CanExecute = がすべてのコントロールではなく、個別の妥当性をチェックする方法がある場合、私は次のコード で個々のコントロールを確認することができますか? – Mitch

+0

私はこれに関するいくつかのアイデアを含むように編集しました。 –

+2

推奨コマンドの使用方法は+1です。コマンドはWPFが真に私をクリックするようにしたものです。 –

1

私はこのためだけに添付プロパティを作成しました:私は私のフォーム上でこのようにそれを使用してい

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> 
関連する問題