2013-08-16 2 views
1

У меня есть приложение MVVM WPF, которое имеет TreeView со всеми статическими элементами, поддерживаемыми на странице XAML. Как узнать в моей модели представления, на которую щелкнут MenuItem, чтобы я мог соответствующим образом отобразить соответствующую страницу.Как узнать, какой элемент treeview нажат, используя mvvm

<TreeView Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="MyTreeViewMenu" 
         VerticalAlignment="Stretch" Width="Auto" Opacity="1" 
        BorderThickness="1" BorderBrush="Black" Grid.Row="2"> 

     <TreeViewItem Header="Country" Width="Auto" HorizontalAlignment="Stretch" 
         ></TreeViewItem> 

     <TreeViewItem Header="View Details" Width="Auto" HorizontalAlignment="Stretch" IsEnabled="False"> 
       <TreeViewItem Header="User" /> 
       <TreeViewItem Header="Group" /> 
       <TreeViewItem Header="User Group" /> 
      </TreeViewItem> 
    </TreeView> 

ответ

2

Я полагаю, что Selected событие будет иметь тот же эффект, как click в вашем случае. Для того, чтобы определить, какой один TreeViewItem был выбран, вы должны добавить событие Trigger:

<TreeView Height="Auto" HorizontalAlignment="Stretch" Margin="0" Name="MyTreeViewMenu" 
         VerticalAlignment="Stretch" Width="Auto" Opacity="1" 
        BorderThickness="1" BorderBrush="Black" Grid.Row="2"> 

     <TreeViewItem Header="Country" Width="Auto" HorizontalAlignment="Stretch"></TreeViewItem>  
     <TreeViewItem Header="View Details" Width="Auto" HorizontalAlignment="Stretch" IsEnabled="False"> 
       <TreeViewItem Header="User" /> 
       <TreeViewItem Header="Group" /> 
       <TreeViewItem Header="User Group" /> 
      </TreeViewItem> 
       <i:Interaction.Triggers> 
        <i:EventTrigger EventName="SelectedItemChanged"> 
         <i:InvokeCommandAction 
         Command="{Binding selectItemCommand}" 
         CommandParameter="{Binding SelectedItem, ElementName=MyTreeViewMenu}"/> 
        </i:EventTrigger> 
       </i:Interaction.Triggers> 
</TreeView> 

В результате вы можете использовать и определить, какой элемент был выбран с помощью параметра, переданного Command.

ViewModel должен выглядеть примерно так:

private ICommand _selectItemCommand; 
public ICommand selectItemCommand 
{ 
    get 
    { 
     return _selectItemCommand ?? (_selectItemCommand = new RelayCommand(param => this.LoadPage(param))); 
    } 
} 

private void LoadPage(object selectedMenuItem) 
{ 
     ... 
} 
+0

'TreeViewItem.Selected' является событие не так ли? Как вы используете 'StaticResource' для соответствия' Command' с событием? Кроме того, запрос был для решения MVVM. – Sheridan

+0

@Sheridan Да .. Ответ обновлен. –

+0

Добавлена ​​команда и свойства в моей модели. Хотя команда вызывается при выборе пункта меню, но как получить selectedmenuItem? См. Ниже комментарии. – user2519971

2

Посмотрите на TreeView.SelectedItem Property страницу в MSDN.

Вы можете связать непосредственно к TreeView.SelectedItem собственности:

<TreeView ItemsSource="{Binding Items}" SelectedItem="{Binding Item, Mode=OneWay}" /> 

Заметим, что свойство TreeView.SelectedItem только для чтения только, так что вы должны использовать OneWay связывания ... это означает, что вы не можете установить выбранный элемент из вашей модели просмотра. Для этого вам нужно будет создать свой собственный двухпозиционный элемент с помощью Attached Property.

EDIT >>>

Мои извинения @ Scroog1, я обычно используют AttachedProperty, чтобы сделать это. Вы правы, что даже с привязкой OneWay с этим методом возникает ошибка. К сожалению, мой код AttachedProperty длинный, но есть и другой способ сделать это.

я не обязательно рекомендовать, как это никогда не очень хорошая идея, чтобы поместить свойства пользовательского интерфейса в ваших объектов данных, но если добавить IsSelected свойство к объекту данных, то вы можете привязать его непосредственно к TreeViewItem.IsSelected собственности:

<TreeView ItemsSource="Items" HorizontalAlignment="Stretch" ... Name="MyTreeViewMenu"> 
    <TreeView.ItemContainerStyle> 
     <Style TargetType="{x:Type TreeViewItem}"> 
      <Setter Property="IsSelected" Value="{Binding IsSelected}" /> 
     </Style> 
    </TreeView.ItemContainerStyle> 
</TreeView> 

Я просто искал и нашел «полное» ответ для вас в WPF MVVM TreeView SelectedItem пост здесь на StackOverflow.

Альтернативно, существует другой способ ... вы также можете использовать свойства TreeView.SelectedValue и TreeView.SelectedValuePath. Основная идея заключается в том, чтобы установить свойство TreeView.SelectedValuePath на имя свойства в вашем объекте данных. Когда элемент выбран, свойство TreeView.SelectedValue будет установлено в значение этого свойства выбранного элемента данных. Дополнительную информацию об этом методе можно найти на странице How to: Use SelectedValue, SelectedValuePath, and SelectedItem в MSDN. Обычно это работает лучше всего, если у вас есть уникально идентифицируемое свойство, такое как идентификатор какого-либо типа. Этот пример кода из MSDN:

<TreeView ItemsSource="{Binding Source={StaticResource myEmployeeData}, 
XPath=EmployeeInfo}" Name="myTreeView" SelectedValuePath="EmployeeNumber" /> 

<TextBlock Margin="10">SelectedValuePath: </TextBlock> 
<TextBlock Margin="10,0,0,0" Text="{Binding ElementName=myTreeView, 
Path=SelectedValuePath}" Foreground="Blue"/> 

<TextBlock Margin="10">SelectedValue: </TextBlock> 
<TextBlock Margin="10,0,0,0" Text="{Binding ElementName=myTreeView, 
Path=SelectedValue}" Foreground="Blue"/> 
+0

Я получаю ошибку '' SelectedItem 'свойство доступно только для чтения и не может быть установлено из разметки.', Когда я пытаюсь это сделать. – Scroog1

+0

Пожалуйста, правильно прочитайте мой ответ, чтобы исправить вашу проблему ... обратите внимание на бит о 'you * must * use OneWay binding'. – Sheridan

+0

Я использовал привязку OneWay. – Scroog1

0

В дополнение к обязательным к свойству TreeView.SelectedItem:

При использовании MVVM он помог мне перестать думать о событиях в UI и начать думать о состоянии в UI.

Вы можете привязать ViewModel к свойствам представления. Поэтому в целом я пытаюсь привязать SelectedItem к свойству ViewModel, чтобы ViewModel знал, что выбрано.

Точно так же вы можете добавить свойство к элементам ViewModel, отображаемым с именем Selected, и привязать это свойство к флажку в представлении. Таким образом вы можете включить множественный выбор и получить доступ к выбранным элементам легко в ViewModel.

0

Для полноты здесь присоединенные собственностей и TreeView подкласса опция:

опции Attached свойства

public static class TreeViewSelectedItemHelper 
{ 
    public static readonly DependencyProperty BindableSelectedItemProperty 
     = DependencyProperty.RegisterAttached(
      "BindableSelectedItem", 
      typeof (object), 
      typeof (TreeViewSelectedItemHelper), 
      new FrameworkPropertyMetadata(false, 
              OnSelectedItemPropertyChanged) 
       { 
        BindsTwoWayByDefault = true 
       }); 

    public static object GetBindableSelectedItem(TreeView treeView) 
    { 
     return treeView.GetValue(BindableSelectedItemProperty); 
    } 

    public static void SetBindableSelectedItem(
     TreeView treeView, 
     object selectedItem) 
    { 
     treeView.SetValue(BindableSelectedItemProperty, selectedItem); 
    } 

    private static void OnSelectedItemPropertyChanged(
     DependencyObject sender, 
     DependencyPropertyChangedEventArgs args) 
    { 
     var treeView = sender as TreeView; 
     if (treeView == null) return; 
     SetBindableSelectedItem(treeView, args.NewValue); 
     treeView.SelectedItemChanged -= HandleSelectedItemChanged; 
     treeView.SelectedItemChanged += HandleSelectedItemChanged; 
     if (args.OldValue != args.NewValue) 
      SetSelected(treeView, args.NewValue); 
    } 

    private static void SetSelected(ItemsControl treeViewItem, 
            object itemToSelect) 
    { 
     foreach (var item in treeViewItem.Items) 
     { 
      var generator = treeViewItem.ItemContainerGenerator; 
      var child = (TreeViewItem) generator.ContainerFromItem(item); 
      if (child == null) continue; 
      child.IsSelected = (item == itemToSelect); 
      if (child.HasItems) SetSelected(child, itemToSelect); 
     } 
    } 

    private static void HandleSelectedItemChanged(
     object sender, 
     RoutedPropertyChangedEventArgs<object> args) 
    { 
     if (args.NewValue is TreeViewItem) return; 
     var treeView = sender as TreeView; 
     if (treeView == null) return; 
     var binding = BindingOperations.GetBindingExpression(treeView, 
      BindableSelectedItemProperty); 
     if (binding == null) return; 
     var propertyName = binding.ParentBinding.Path.Path; 
     var property = binding.DataItem.GetType().GetProperty(propertyName); 
     if (property != null) 
      property.SetValue(binding.DataItem, treeView.SelectedItem, null); 
    } 
} 

варианта Подкласса

public class BindableTreeView : TreeView 
{ 
    public BindableTreeView() 
    { 
     SelectedItemChanged += HandleSelectedItemChanged; 
    } 

    public static readonly DependencyProperty BindableSelectedItemProperty = 
     DependencyProperty.Register(
      "BindableSelectedItem", 
      typeof (object), 
      typeof (BindableTreeView), 
      new FrameworkPropertyMetadata(
       default(object), 
       OnBindableSelectedItemChanged) {BindsTwoWayByDefault = true}); 

    public object BindableSelectedItem 
    { 
     get { return GetValue(BindableSelectedItemProperty); } 
     set { SetValue(BindableSelectedItemProperty, value); } 
    } 

    private static void OnBindableSelectedItemChanged(
     DependencyObject d, 
     DependencyPropertyChangedEventArgs e) 
    { 
     var treeView = d as TreeView; 
     if (treeView != null) SetSelected(treeView, e.NewValue); 
    } 

    private static void SetSelected(ItemsControl treeViewItem, 
            object itemToSelect) 
    { 
     foreach (var item in treeViewItem.Items) 
     { 
      var generator = treeViewItem.ItemContainerGenerator; 
      var child = (TreeViewItem) generator.ContainerFromItem(item); 
      if (child == null) continue; 
      child.IsSelected = (item == itemToSelect); 
      if (child.HasItems) SetSelected(child, itemToSelect); 
     } 
    } 

    private void HandleSelectedItemChanged(
     object sender, 
     RoutedPropertyChangedEventArgs<object> e) 
    { 
     SetValue(BindableSelectedItemProperty, SelectedItem); 
    } 
} 
Смежные вопросы