2013-07-16 2 views
0

Я пытаюсь получить выбранный элемент из моего TreeView, но с некоторой проблемой. Я следую за MVVM archetecture. My ViewModel содержит коллекцию класса, который находится в моей модели. Поэтому я привязал ItemSource TreeView к этой коллекции. Я хочу привязать выбранный элемент моего TreeView к элементу привязанной коллекции. Как это сделать. Вот код для SelectedItem и IsSelected Property.SelectedItem в TreeView

private static sourceData _selectedItem = null; 
    /// <summary> 
    /// Selected Item in the tree 
    /// </summary> 
    public static sourceData SelectedItem 
    { 
     get { return _selectedItem; } 
     set 
     { 
      if (_selectedItem != value) 
      { 
       _selectedItem = value; 
      } 
     } 
    } 

    private bool _isSelected; 
    /// <summary> 
    /// Get/Set for Selected node 
    /// </summary> 
    public bool IsSelected 
    { 
     get { return _isSelected; } 
     set 
     { 
      if (_isSelected != value) 
      { 
       _isSelected = value; 

       if (_isSelected) 
       { 
        SelectedItem = this; 
        OnPropertyChanged("IsSelected"); 
       } 
      } 
     } 
    } 

    /// <summary> 
    /// Property changed event 
    /// </summary> 
    public event PropertyChangedEventHandler PropertyChanged; 
    /// <summary> 
    /// Property changed event handler 
    /// </summary> 
    /// <param name="propertyName"></param> 
    protected virtual void OnPropertyChanged(string propertyName) 
    { 
     var handler = this.PropertyChanged; 
     if (handler != null) 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
    } 

Когда я отладки это, внутр SelectedItem = this; «это» указатель содержит коллекцию, к которой переплетены мой TreeView. Мне нужно было иметь SelectedDataSource, чтобы я мог назначить его выбранному элементу. Как я могу заставить TreeView вернуть мне выбранный элемент в коллекции?

FYI, это мой XAML код для TreeView

<TreeView Margin="5,0,0,0" ItemsSource="{Binding SourceData}" Width="390"> 
        <TreeView.ItemContainerStyle> 
         <Style TargetType="{x:Type TreeViewItem}"> 
          <Setter Property="IsSelected" Value="{Binding DataContext.IsSelected, Mode=TwoWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" /> 
          <Setter Property="ContextMenu"> 
           <Setter.Value> 
            <ContextMenu Name="contextMenu" DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}" > 
             <MenuItem Name="menuItem" Header="Rename" Command="{Binding RenameCommand}" /> 
            </ContextMenu> 
           </Setter.Value> 
          </Setter> 
          <Style.Triggers> 
           <Trigger Property="IsSelected" Value="True"> 
           </Trigger> 
          </Style.Triggers> 
         </Style> 
        </TreeView.ItemContainerStyle> 

P.S: Если я пишу код выше в моей модели, я получаю все работает прекрасно. Но я не могу изменить вышеуказанный код в модели, он должен быть в виртуальной машине.

Любая помощь будет очень признательна.

Благодаря

+0

Возможный дубликат http://stackoverflow.com/questions/1000040/selecteditem-in-a-wpf-treeview – Nitesh

+0

Я использую Attached Behavior для привязки к ICommand в моей виртуальной машине. Он чист, но вы должны помнить, что TV SelectedItem является свойством readonly, поэтому виртуальная машина может только проверить его. –

+0

Я только хочу прочитать SelectedItem. Мне не нужно его устанавливать. Итак, как вы используете Attached поведение для привязки к ICommmand в VM? – WAQ

ответ

0

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

public static class TvBehaviour 
    { 
     #region TvSelectedItemChangedBehaviour (Attached DependencyProperty) 
     public static readonly DependencyProperty TvSelectedItemChangedBehaviourProperty = 
      DependencyProperty.RegisterAttached("TvSelectedItemChangedBehaviour", 
               typeof (ICommand), 
               typeof (TvBehaviour), 
               new PropertyMetadata(
                OnTvSelectedItemChangedBehaviourChanged)); 

     public static void SetTvSelectedItemChangedBehaviour(DependencyObject o, ICommand value) 
     { 
      o.SetValue(TvSelectedItemChangedBehaviourProperty, value); 
     } 
     public static ICommand GetTvSelectedItemChangedBehaviour(DependencyObject o) 
     { 
      return (ICommand) o.GetValue(TvSelectedItemChangedBehaviourProperty); 
     } 
     private static void OnTvSelectedItemChangedBehaviourChanged(DependencyObject d, 
                    DependencyPropertyChangedEventArgs e) 
     { 
      TreeView tv = d as TreeView; 
      if (tv != null) 
      { 
       tv.SelectedItemChanged += (s, a) => 
        { 
         GetTvSelectedItemChangedBehaviour(tv).Execute(a.NewValue); 
         a.Handled = true; 
        }; 
      } 
     } 
     #endregion 

}

Затем импортировать пространство имен класса, в свою Xaml (используя Xmlns). Вы можете объявить TreeView вдоль этих линий ...

<TreeView ItemsSource="{Binding MyList}" 
       ItemTemplate="{StaticResource My_data_template}" 
       tvBinding:TvBehaviour.TvSelectedItemChangedBehaviour="{Binding    
          SelectedItemCommand}" 
       SelectedValuePath="Name" 
       > 
    </TreeView> 

Это «провода» Поведение TV к ICommand в ВМ. Наконец, объявите ICommand в вашей VM ...

общественный ICommand SelectedItemCommand {get; задавать; }

и инициализировать его ...

SelectedItemCommand = new RelayCommand(ExecuteSelectedItemCommand, 
             CanExecuteSelectedItemCommand); 

А затем реализовать ваши делегаты ...

private void ExecuteSelectedItemCommand(object obj) 
    { 
     // downcast 'obj' to get the instance of the selected item 
    } 
    private bool CanExecuteSelectedItemCommand(object obj) 
    { 
     return true; 
    } 

Когда пользователь выбирает телевизионный пункт, ваш «выполнить» делегат получит в штучной упаковке экземпляр элемента, и вы можете его удалить из него и т. д. и т. д. и т. д.

Обратите внимание, что приложенное поведение в этом примере предполагает, что время жизни телевизора такое же, как и приложение, в противном случае вам нужно проводя приложенное поведение. Он также предполагает, что TV ItemsSource привязан к чему-то разумному.

Это решит проблему получения TV SelectedItem, оставаясь при этом совместимым с MVVM (если существует такая совместимость с MVVM-совместимостью).

Класс Relay Command, который я использовал, был взят из связанной статьи в MSDN. Для справки, здесь ...

public class RelayCommand : ICommand 
{ //http://msdn.microsoft.com/en-us/magazine/dd419663.aspx 
    public RelayCommand(Action<object> execute, Predicate<object> canExecute) 
    { 
     _execute = execute; 
     _canExecute = canExecute; 
    } 
    public bool CanExecute(object parameter) 
    { 
     return _canExecute(parameter); 
    } 
    public event EventHandler CanExecuteChanged 
    { 
     add { CommandManager.RequerySuggested += value; } 
     remove { CommandManager.RequerySuggested -= value; } 
    } 
    public void Execute(object parameter) 
    { 
     _execute(parameter); 
    } 
    private readonly Action<object> _execute; 
    private readonly Predicate<object> _canExecute; 
} 

Используйте ссылку MSDN выше, чтобы получить более подробную информацию об этом классе.

+0

Я не могу выполнить инициализацию SelectedItemCommand. Он говорит, что у RelayCommand есть некоторые недопустимые аргументы. Когда я удаляю аргументы ExecuteSelectedItemCommand, ошибка исчезает. но это не помогает мне – WAQ

+0

Возможно, другая версия. Ответ отредактирован. Я включил версию ORIGINAL в редактирование моего ответа. В этой версии делегаты строго типизированы (что вам и нужно). Попробуйте это вместо этого ... –

Смежные вопросы