TreeView中的SelectedItem

时间:2013-07-16 12:22:35

标签: wpf xaml treeview wpf-controls

我正在尝试从TreeView中获取所选项目,但遇到了一些问题。 我正在关注MVVM archetecture。我的ViewModel包含我的模型中的类的集合。所以我已经将TreeView的ItemSource绑定到该集合。我想将TreeView的selectedItem绑定到绑定集合的项目。我怎么做。这是SelectedItem和IsSelected属性的代码。

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

当我调试它时,int SelectedItem = this;'this'指针包含我的树视图绑定到的集合。我需要一个SelectedDataSource,以便我可以将它分配给选定的Item。如何让我的TreeView返回集合中的selectedItem?

FYi,这是我对TreeView的XAML代码

<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:如果我在我的模型中编写上面的代码,我会让一切都运行得很好。但是我不能在Model中使用上面的代码,它必须在VM中。

任何帮助将不胜感激。

谢谢

1 个答案:

答案 0 :(得分: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>

将电视行为“连接”到VM中的ICommand。最后,在你的VM中声明ICommand ......

public 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绑定了一些合理的东西。

这将解决在保持MVVM兼容的同时获取TV SelectedItem的问题(如果存在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链接获取有关此课程的更多信息。