0

我试图从我的 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 返回给我?

仅供参考,这是我的 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中。

4

1 回答 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。最后,在你的虚拟机中声明 ICommand ......

公共 ICommand SelectedItemCommand { 获取;放; }

并初始化它...

 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 链接获取有关此类的更多信息。

于 2013-07-16T13:42:35.787 回答