2010-11-21 7 views
0

データナビゲータとして使用するUserControlを作成しました。次のように私は(DependencyPropertyには暗黙の)このコントロールで2 DependencyPropertiesを定義した:WPF UserControlでボタンの有効状態を動的に変更するための条件付きデータトリガー

public ICollection DataCollection 
{ 
    get { return GetValue(DataCollectionProperty) as ICollection; } 
    set { SetValue(DataCollectionProperty, value); } 
} 

public ICollectionView View 
{ 
    get { return (DataCollection == null ? null : CollectionViewSource.GetDefaultView(DataCollection)); } 
} 

はその後、私は基本的なナビゲーション操作を実行するために4つのボタンを入れてきました(最初、前、次、最後)。各ボタンには、次のスタイルを取得します。

<Style x:Key="NavButtonStyle" TargetType="{x:Type Button}"> 
    <Style.Triggers> 
     <DataTrigger Binding="{Binding DataCollection}" Value="{x:Null}"> 
      <Setter Property="IsEnabled" Value="False" /> 
     </DataTrigger> 
    </Style.Triggers> 
</Style> 

すべてこのトリガーDataCollectionたDependencyPropertyがnullの場合、このように、RelativeResource TemplatedParentは、各ボタンのDataContextのとして渡されると仮定し、チェックするためにされない:

<Button (...) DataContext="{RelativeSource TemplatedParent}"> 

は、その後、私は比較演算と比較した値に基づき、値を比較し、trueまたはfalseを返すために、次のMarkupExtensionを作成:

[MarkupExtensionReturnType(typeof(bool))] 
public class ComparisonBinding : BindingDecoratorBase 
{ 
    public ComparisonOperation Operation { get; set; } 
    public object Comparand { get; set; } 

    public override object ProvideValue(IServiceProvider provider) 
    { 
     base.ProvideValue(provider); 

     DependencyObject targetObject; 
     DependencyProperty targetProperty; 
     bool status = TryGetTargetItems(provider, out targetObject, out targetProperty); 

     if (status && Comparand != null) 
     { 
      if (Comparand is MarkupExtension) 
       Comparand = (Comparand as MarkupExtension).ProvideValue(provider); 
      return Compare(targetObject.GetValue(targetProperty), Comparand, Operation); 
     } 

     return false; 
    } 

    private static bool Compare(object source, object target, ComparisonOperation op) 
} 

最後に、このMEを使用して、各ボタンの「有効化」条件をテストしました。ここでまずボタンの条件です:

<Button (...) DataContext="{RelativeSource TemplatedParent}" 
    IsEnabled="{DynamicResource {mark:ComparisonBinding Path=View.CurrentPosition, RelativeSource={RelativeSource TemplatedParent}, Comparand={Binding RelativeSource={RelativeSource TemplatedParent}, Path=DataCollection.Count}, Operation=EQ}}"> 

残念ながら、このソリューションが動作しませんでした。このデザインタイムの例外が発生し続ける:

InvalidOperationException:ビューツリーの一部ではないViewNodeのNodePathを取得できません。

誰かがより良い解決策を持っていますか?多分私は大砲でフライを殺そうとしています。 :)

ありがとうございます。 Eduardo Melo

答えて

0

私の意見では、ボタンの有効/無効機能を実装する最も良い方法は、ICommandインターフェイスを使用してCanExecuteメソッドを使用することです。この目的のために、MVVMLightのPrismまたはRelayCommandのDelegateCommandのような軽量な実装を使用することができます。本当に効率を上げたい場合は、CommandManagerでコマンドを登録しないで、コードで使用できる特定の条件でCanExecuteChangedをトリガーします。

これは、WPF開発に最適な方法である、ユーザーコントロールにマイクロViewModel(ICommandインスタンスとそのExecuteメソッドとCanExecuteメソッドの実装)が含まれることを意味しますとにかくその場合、XAMLで必要なのは、ボタンのCommandプロパティを適切なICommandにバインドすることだけです。これにより、コマンド(機能的な観点からは「タスク」と見なすことができます)を、他の呼び出し元にもきれいに公開します。

たとえば、コントロールによってICommandが公開され、コントロールテンプレート内のボタンが(RelativeSource Selfを使用して)同じコマンドにバインドされていることは完全に正当です。可視性を他のプロパティ(UseBuiltInButtons)にバインドすることもできます。また、後でいくつかの魅力的なインターフェイスでコントロールを統合したい場合は、ボタンを非表示にして外部のものを同じICommandにリンクするだけです。

それが助けてくれるのか混乱しているのかを教えてください。私はその問題についてもっと光を当てようとします!もちろん、これは単なるアイデアであり、他にも同様に良いアイデアがあるかもしれません。

+0

こんにちは、アレックス!私はWPFと.NETフレームワークが初めてです。最近私はコマンドについて読んだことがあり、それが目的です。あなたの考え方に沿って、私はそれが私が提案したものより良い解決策であることに気付きました。しかし、私が得られなかったのは、あなたが話したマイクロビューモデルです。もう少し詳しく説明できますか?ありがとう! – EdMelo

+0

私はMVVMパターンが大好きなので、ViewModelはどこにでも言及したいと思っています。実際には、適切なパラメータを受け取ったCommandオブジェクト自体を含め、コマンドを扱うコードをどこにでも置くことができます。私の通常の最初の本能は、ロジックを処理するViewModelにそれを配置し、そのViewModelをView(この場合はコントロール)に関連付けさせることです。しかし、ユーザーコントロールの開発では、コントロール自体のICommandを定義し、ControlTemplateのTemplatedParentを使用してICommandsをバインドするだけで多くの成功を収めました。 –

関連する問題