2012-06-17 2 views
8

私はウィンドウの左側にWPF TreeViewを持つMVVMアプリケーションを持っています。 右側の詳細パネルは、選択したツリーノードに応じて内容を変更します。マウスかキーで選択されているか調べるには?

ユーザーがノードを選択すると、詳細内容パネルがすぐに変更されます。 ユーザーがノードをクリックした場合は望ましいですが、ユーザーがキーの下/上を使用してツリーをナビゲートすると、コンテンツの変更が遅れることがあります。 (少なくともWindows XPではWindows XPと同じ動作) マウスまたはキーボードでノードが選択されている場合は、ViewModelで知っている必要があります。

どうすればこの問題を解決できますか?

更新:

これは、したがって、これは適切な場所であれば、私はわからないんだけど、私はコミュニティが、私はその間に何をしたか知らせてほしい私の最初の投稿です。ここに私自身の解決策があります。私は専門家ではないので、良い解決策であるかどうかはわかりません。しかし、それは私のために働く、それが他人を助けるなら私は幸せになるだろう。バグ修正、改善、またはより良い解決策が高く評価されています。

私はHasMouseFocus ...
は(最初に私がMouseEnterEventを使用しますが、ユーザーがキーアップ/ダウンでツリーをナビゲートし、マウスポインタが任意のナビゲート木の上にランダムであれば、これはうまく動作しない添付プロパティの下に作成項目、その場合には、詳細はすぐに更新されるため。)

public static bool GetHasMouseFocus(TreeViewItem treeViewItem) 
{ 
    return (bool)treeViewItem.GetValue(HasMouseFocusProperty); 
} 

public static void SetHasMouseFocus(TreeViewItem treeViewItem, bool value) 
{ 
    treeViewItem.SetValue(HasMouseFocusProperty, value); 
} 

public static readonly DependencyProperty HasMouseFocusProperty = 
    DependencyProperty.RegisterAttached(
    "HasMouseFocus", 
    typeof(bool), 
    typeof(TreeViewItemProperties), 
    new UIPropertyMetadata(false, OnHasMouseFocusChanged) 
); 

static void OnHasMouseFocusChanged(
    DependencyObject depObj, DependencyPropertyChangedEventArgs e) 
{ 
    TreeViewItem item = depObj as TreeViewItem; 
    if (item == null) 
    return; 

    if (e.NewValue is bool == false) 
    return; 

    if ((bool)e.NewValue) 
    { 
    item.MouseDown += OnMouseDown; 
    item.MouseLeave += OnMouseLeave; 
    } 
    else 
    { 
    item.MouseDown -= OnMouseDown; 
    item.MouseLeave -= OnMouseLeave; 
    } 
} 

/// <summary> 
/// Set HasMouseFocusProperty on model of associated element. 
/// </summary> 
/// <param name="sender"></param> 
/// <param name="e"></param> 
static void OnMouseDown(object sender, MouseEventArgs e) 
{ 
    if (sender != e.OriginalSource) 
    return; 

    TreeViewItem item = sender as TreeViewItem; 
    if ((item != null) & (item.HasHeader)) 
    { 
    // get the underlying model of current tree item 
    TreeItemViewModel header = item.Header as TreeItemViewModel; 
    if (header != null) 
    { 
     header.HasMouseFocus = true; 
    } 
    } 
} 

/// <summary> 
/// Clear HasMouseFocusProperty on model of associated element. 
/// </summary> 
/// <param name="sender"></param> 
/// <param name="e"></param> 
static void OnMouseLeave(object sender, MouseEventArgs e) 
{ 
    if (sender != e.OriginalSource) 
    return; 

    TreeViewItem item = sender as TreeViewItem; 
    if ((item != null) & (item.HasHeader)) 
    { 
    // get the underlying model of current tree item 
    TreeItemViewModel header = item.Header as TreeItemViewModel; 
    if (header != null) 
    { 
     header.HasMouseFocus = false; 
    } 
    } 
} 

...とTreeView.ItemContainerStyle

<TreeView.ItemContainerStyle> 
     <Style TargetType="{x:Type TreeViewItem}" > 
     <!-- These Setters binds some properties of a TreeViewItem to the TreeViewItemViewModel. --> 
     <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
     <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> 
     <Setter Property="ToolTip" Value="{Binding Path=CognosBaseClass.ToolTip}"/> 
     <!-- These Setters applies attached behaviors to all TreeViewItems. --> 
     <Setter Property="properties:TreeViewItemProperties.PreviewMouseRightButtonDown" Value="True" /> 
     <Setter Property="properties:TreeViewItemProperties.BringIntoViewWhenSelected" Value="True" /> 
     <Setter Property="properties:TreeViewItemProperties.HasMouseFocus" Value="True" /> 
     </Style> 
    </TreeView.ItemContainerStyle> 
に適用し

プロパティは、添付プロパティのパスです。 HasMousefocusPropertyがtrueの場合

xmlns:properties="clr-namespace:WPF.MVVM.AttachedProperties;assembly=WPF.MVVM" 

はその後、私のViewModelに、私はすぐに詳細パネル(GridViewコントロール)を更新。 falseの場合は、単にDispatcherTimerを起動し、現在選択されている項目をTagとして適用します。間隔が500msになると、Tick-Eventは詳細を適用しますが、選択した項目がTagと同じである場合に限ります。

/// <summary> 
/// This property is beeing set when the selected item of the tree has changed. 
/// </summary> 
public TreeItemViewModel SelectedTreeItem 
{ 
    get { return Property(() => SelectedTreeItem); } 
    set 
    { 
    Property(() => SelectedTreeItem, value); 
    if (this.SelectedTreeItem.HasMouseFocus) 
    { 
     // show details for selected node immediately 
     ShowGridItems(value); 
    } 
    else 
    { 
     // delay showing details 
     this._selctedNodeChangedTimer.Stop(); 
     this._selctedNodeChangedTimer.Tag = value; 
     this._selctedNodeChangedTimer.Start(); 
    } 
    } 
} 
+0

次のようにSOの質問では、キーバインディングの問題を扱います。http://stackoverflow.com/a/7086853/1416258およびhttp://stackoverflow.com/a/918062/1416258個人的な状況は、周りを遊んで、または誰かがあなたに魚を与えるのを待つ。 –

+0

多くの感謝@Geoist。 Cammandバインディングを使用すると、ユーザーが指定したキーを押すとすぐにViewModelにフラグを設定できます。しかし、ユーザーが別のツリーノードを選択したとき(またはその前に)、このフラグをクリアする必要があります。何か案は? – AelanY

+0

@AelanYはい、あなたはこのフラグをリセットする必要があります。あなたの詳細パネルのリフレッシュを開始しているロジックに最適な場所が必要です。 – akjoshi

答えて

2

あなたのTreeView(それを有するか、またはユーザーコントロール)用OnPreviewKeyDownを処理し、プログラムであなたのViewModelにフラグを設定し、さわやか詳細パネルながら、それを考慮することができます -

protected override void OnPreviewKeyDown(System.Windows.Input.KeyEventArgs e) 
{ 
    switch(e.Key) 
    { 
     case Key.Up: 
     case Key.Down: 
      MyViewModel.IsUserNavigating = true; 
      break; 
    } 
} 

同様のapprochと他の解決策は、このSO質問に記載されている -

How can I programmatically navigate (not select, but navigate) a WPF TreeView?

更新: [AalanYのコメントへの応答]

MVVMを壊すことはありませんが、ビューにコードビハインドを持つことに問題はないと思います。

記事、 WPF Apps With The Model-View-ViewModel Design Pattern

、ジョシュ・スミスである著者は言う:うまく設計MVVMアーキテクチャで

、ほとんどのビュー ための分離コードが空である、または、せいぜい、コードのみが含まれている必要がありますそのビュー内に含まれているコントロールとリソースを操作します( )。時には、このようなイベントをフックまたはその他のViewModel 自体から呼び出すことが非常に困難であろう方法 を呼び出すよう、またのViewModelオブジェクトと を相互作用ビューの分離コードでコードを記述する必要 です。ツリービュー、データグリッドや3'rdパーティ製のコントロールのような複雑なコントロールを使用する必要があり、特別に私の経験では、それは(かなりの大きさの)企業を構築することは不可能です

任意のコードビハインドを持つことなく、アプリケーション、。

+0

@akjoshiさんのお返事ありがとうございますが、私はMVVMパターンを使用していますので、コードを残したくありません。 – AelanY

+0

もう一度@akjoshi、私はすでにジョシュ・スミスのこの偉大な記事を読んで、もちろんあなたは正しいです。私の解決策についてどう思いますか?上記の私の更新を参照してください... – AelanY

+0

@AelanY XAMLのツリービューにアタッチすることができ、再利用性の要素を持っているので、あなたのソリューションは見た目がよくなります。これは、イベントハンドラを使用し、ViewModelフラグを更新することとほぼ同じです。 – akjoshi

関連する問題