2013-07-08 3 views
0

У меня возникла проблема со следующим кодом. У меня есть элемент управления TreeView, связанный с коллекцией. Желательно, чтобы TreeView заполнил желаемые результаты. Однако, если свойство IsSelected и команда Click ContextMenu не запускаются. Ниже приведен код XAML.Невозможно активировать события, связанные с TreeView

<UserControl x:Class="Plan.Views.PadView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      xmlns:v="clr-namespace:Planner.Views" 
      xmlns:vm="clr-namespace:Planner.ViewModels" 
    <Grid> 
     <StackPanel Orientation="Vertical"> 
      <Grid> 
       <Grid.RowDefinitions> 
        <RowDefinition Height="Auto" /> 
       </Grid.RowDefinitions> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*" /> 
       </Grid.ColumnDefinitions> 
       <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" OpacityMask="#FFECF5F5"> 
        <TreeView ItemsSource="{Binding Pads}" Name="tree_View" Width="190"> 
         <TreeView.ItemContainerStyle > 
          <Style TargetType="{x:Type TreeViewItem}"> 
           <Setter Property="IsSelected" Value="{Binding WellPadViewModel.IsSelected}" /> 
           <Setter Property="ContextMenu"> 
            <Setter.Value> 
             <ContextMenu> 
              <MenuItem Header="Rename" Command="{Binding RelativeSource={RelativeSource AncestorType={x:Type TreeView}}, Path=DataContext.RenameCommand}" /> 
             </ContextMenu> 
            </Setter.Value> 
           </Setter> 
           <Style.Triggers> 
            <Trigger Property="IsSelected" Value="True"> 
            </Trigger> 
           </Style.Triggers> 
          </Style> 
         </TreeView.ItemContainerStyle > 
         <TreeView.ItemTemplate> 
          <HierarchicalDataTemplate ItemsSource="{Binding Members}"> 
           <StackPanel Orientation="Horizontal"> 
            <TextBlock Text="{Binding Name}" > 
             <TextBlock.InputBindings> 
               <KeyBinding Key="F2" Command="{Binding RenameCommand}"/> 
              </TextBlock.InputBindings> 
            </TextBlock> 
           </StackPanel> 
         </HierarchicalDataTemplate> 
         </TreeView.ItemTemplate> 
        </TreeView> 
       </StackPanel> 
      </Grid> 
     </StackPanel> 
    </Grid> 
</UserControl> 

А вот мой ViewModel

using System; 
using System.Collections.ObjectModel; 
using System.Windows; 
using System.Windows.Input; 
using System.ComponentModel; 
using WPFApplication; 

namespace FieldPlanner.ViewModels 
{ 
    public class PlanViewModel : BaseViewModel 
    { 
     Collection<Pads> pads = new Collection<Pads>(); 
     public PlanViewModel() 
     { 
      IsSelected = true; 
      pads = new Collection<Pad>(); 
     } 

     private ICommand _RenameCommand; 

     public ICommand RenameCommand 
     { 
      get 
      { 
       if (_RenameCommand == null) 
       { 
        _RenameCommand = new RelayCommand1((o) => 
        { 
         // Your logic should go here 
         MessageBox.Show("Please rename me"); 
        }); 
       } 
       return _RenameCommand; 
      } 
     } 

     public ObservableCollection<PadInfo> Members { get; set; } 

     private static object _selectedItem = null; 
     // This is public get-only here but you could implement a public setter which also selects the item. 
     // Also this should be moved to an instance property on a VM for the whole tree, otherwise there will be conflicts for more than one tree. 
     public static object SelectedItem 
     { 
      get { return _selectedItem; } 
      private set 
      { 
       if (_selectedItem != value) 
       { 
        _selectedItem = value; 
        OnSelectedItemChanged(); 
       } 
      } 
     } 

     public static void OnSelectedItemChanged() 
     { 
      // Raise event/do other things 
     } 

     private bool _isSelected; 
     public bool IsSelected 
     { 
      get { return _isSelected; } 
      set 
      { 
       if (_isSelected != value) 
       { 
        _isSelected = value; 
        OnPropertyChanged("IsSelected"); 
        if (_isSelected) 
        { 
         SelectedItem = this; 
        } 
       } 
      } 
     } 

     public event PropertyChangedEventHandler PropertyChanged; 
     protected virtual void OnPropertyChanged(string propertyName) 
     { 
      var handler = this.PropertyChanged; 
      if (handler != null) 
       handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 

    /// <summary> 
    /// Class to hold the Pads info for a tree 
    /// </summary> 
    public class Pad 
    { 
     /// <summary> 
     /// Default Constructor 
     /// </summary> 
     public Pad() 
     { 
      this.Members = new ObservableCollection<PadInfo>(); 
     } 

     /// <summary> 
     /// Name of the pad 
     /// </summary> 
     public string Name { get; set; } 

     /// <summary> 
     /// Members of the pad 
     /// </summary> 
     public ObservableCollection<PadInfo> Members { get; set; } 
    } 

    /// <summary> 
    /// Class to hold the well and slot IDs snapped to a pad 
    /// </summary> 
    public class PadInfo 
    { 
     /// <summary> 
     /// Slot ID 
     /// </summary> 
     public string SlotID { get; set; } 

     /// <summary> 
     /// Well ID 
     /// </summary> 
     public string WellID { get; set; } 
    } 

    public class RelayCommand1 : ICommand 
    { 
     #region Fields 
     readonly Action<object> _execute; 
     readonly Predicate<object> _canExecute; 
     #endregion // Fields 

     #region Constructors 
     public RelayCommand1(Action<object> execute) 
      : this(execute, null) 
     { 
     } 
     public RelayCommand1(Action<object> execute, Predicate<object> canExecute) 
     { 
      if (execute == null) 
       throw new ArgumentNullException("execute"); 

      _execute = execute; 
      _canExecute = canExecute; 
     } 
     #endregion // Constructors 
     #region ICommand Members 
     // [DebuggerStepThrough] 
     public bool CanExecute(object parameter) 
     { 
      return _canExecute == null ? true : _canExecute(parameter); 
     } 
     public event EventHandler CanExecuteChanged 
     { 
      add { CommandManager.RequerySuggested += value; } 
      remove { CommandManager.RequerySuggested -= value; } 
     } 
     public void Execute(object parameter) 
     { 
      _execute(parameter); 
     } 

     #endregion // ICommand Members 
    } 
} 

Я потратил три дня, чтобы определить проблему, но тщетно до сих пор. Может ли кто-нибудь помочь мне определить проблему. Большое спасибо заранее

ответ

0

У вас есть две проблемы:

IsSelected:

<Setter Property="IsSelected" Value="{Binding WellPadViewModel.IsSelected}" /> 

В TreeViewItem DataContext устанавливается на экземпляр Pad и Pad не обладает свойством IsSelected Вы должны сделать, как н это:

<Setter Property="IsSelected" Value="{Binding DataContext.IsSelected, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}" /> 

Проблема с ContextMenu гораздо более сильная. ContextMenu не находится в VisualTree, поэтому вы не можете привязываться к RelativeSource. Решение здесь WPF Relative source- Cannot find source for binding with reference

С наилучшими пожеланиями

+0

Отлично. Большое спасибо. Это решило половину моей проблемы. Но я не могу запустить триггер ContextMenu. Вероятно, я не получил информацию в ссылке правильно. Не могли бы вы рассказать об этом немного больше. Я считаю, что я очень близок к тому, чтобы запустить событие, хотя :) –

+0

<Свойство Setter = "IsSelected" Value = "{Binding DataContext.IsSelected, RelativeSource = {RelativeSource AncestorType = {x: Тип UserControl}}}" /> Это, похоже, исправило проблему с выбранным пунктом. Свойство увольняется, и я могу установить выбранный элемент, используя это. Но свойство Rename ContextMenu по-прежнему не срабатывает. Вот что я пробовал. Kinldy уточняет, какие параметры I должны быть установлены в соответствии с приведенным выше кодом. –

+0

Вы не можете связываться с RelativeSource, потому что ContextMenu не в VisualTree, поэтому он не может видеть элемент, который вы хотите. Используйте свойство Tag и читайте о PlacementTarget - завтра я отправлю вам код. –

0

Пожалуйста, установите свойство Tag в вашем DataTemplate к TreeViewItem. У меня есть такое:

<DataTemplate> 
    <Grid Width="270" Height="20" Tag="{Binding DataContext, RelativeSource = {RelativeSource AncestorType={x:Type UserControl}}}"> 
      ... 
    <Grid.ContextMenu> 
      <ContextMenu DataContext="{Binding PlacementTarget, RelativeSource={RelativeSource Self}}"> 
       <MenuItem Header="Edit"> 
        <i:Interaction.Triggers> 
         <i:EventTrigger EventName="Click"> 
           <command:EventToCommand Command="{Binding Tag.YOURCOMMAND}"/> 
         </i:EventTrigger> 
        </i:Interaction.Triggers> 
        </MenuItem> 
      </ContextMenu> 
     </Grid.ContextMenu> 
    </Grid> 
</DataTemplate> 

Он должен работать.

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