TreeView中的SelectedItem

问题描述 投票:0回答:1

我正在尝试从TreeView中获取选定的项目,但遇到了一些问题。

我正在关注MVVM架构。我的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,以便可以将其分配给选定的项目。如何使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>

PS:如果我在模型中编写以上代码,我将一切正常运行。但是我不能在Model中编写以上代码,它必须在VM中。

wpf xaml treeview wpf-controls
1个回答
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链接获取有关此类的更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.