Как узнать, выбрано ли оно мышью или клавишей?

У меня есть приложение MVVM с WPF TreeView в левой части окна. Панель сведений справа изменяет содержимое в зависимости от выбранного узла дерева.

Если пользователь выбирает узел, содержимое панели сведений немедленно изменяется. Это желательно, если пользователь нажал на узел, но я хочу отложить изменение содержимого, если пользователь перемещается по дереву с помощью клавиши вниз/вверх. (То же поведение, что и проводник Windows, по крайней мере, под Win 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>

Где properties— это путь к моему прикрепленному свойству.

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

Затем в моей ViewModel, если HasMousefocusPropertyравно true, я немедленно обновляю панель сведений (GridView). Если false, я просто запускаю DispatcherTimer и применяю текущий выбранный элемент в качестве тега. После интервала в 500 мс Tick-Event применяет детали, но только если выбранный элемент все еще совпадает с тегом.

/// <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();
    }
  }
}
8
задан AelanY 18 June 2012 в 19:30
поделиться