0

我对以下代码有问题。我有一个绑定到集合的 TreeView 控件。TreeView 确实填充了所需的结果。然而,“IsSelected”属性和 ContextMenu 的单击命令没有触发。以下是 XAML 代码。

    <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
    }
}

如何识别问题?

4

2 回答 2

0

你有两个问题:

已选中:

<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 相对源 - 无法找到用于绑定参考的源

此致

于 2013-07-08T11:20:58.123 回答
0

请将 DataTemplate 中的 Tag 属性设置为 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>

它应该工作。

于 2013-07-10T08:34:59.757 回答