Xaml中的T​​reeViewItem MVVM IsSelected不会向View-Model发送值

时间:2017-06-13 06:30:40

标签: c# wpf mvvm treeviewitem

我遇到了IsSelected属性的问题。它不会将视图中的值发送到视图模型。我在下面发布了我的代码 视图模型:

public class Viewmodel : INotifyPropertyChanged
{
    private ObservableCollection<int> seznam;
    public ObservableCollection<int> Seznam
    {
        get { return seznam; }
        set
        {
            seznam = value;
        }
    }

    public Viewmodel()
    {
        Seznam = new ObservableCollection<int>();
        for (int i = 0; i < 3; i++)
        {
            Seznam.Add(i);
        }
    }

    bool isSelected;
    public bool IsSelected
    {
        get { return isSelected; }
        set
        {
            isSelected = value;
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;

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

查看:

        <TreeView ItemsSource="{Binding Seznam}">
        <TreeView.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>

它仍然没有停在断点,我把它放在了{return isSelected; }

2 个答案:

答案 0 :(得分:0)

根据您更新的帖子,很明显您尚未正确实施您的视图模型。特别是,您的TreeView.ItemsSource绑定到唯一视图模型的Seznam属性。这是int值的集合。

这意味着您尝试绑定到TreeView属性的IsSelected中每个项容器的数据上下文是int值。当然,int值甚至不具有IsSelected属性。

(顺便说一下,我对your claim that "There are no binding errors"持怀疑态度。如果查看调试输出,你当然应该看到绑定错误,试图绑定到不存在的IsSelected属性。)

考虑一下这一点:假设item容器确实设法绑定到Viewmodel.IsSelected属性。你认为有多少个项目容器?您认为有多少Viewmodel个实例?您应该相信有许多项目容器,即您的收藏中的每个项目一个。并且只有Viewmodel的一个实例。那么,所有这些项目将如何?选择状态甚至映射到单个Viewmodel.IsSelected属性?

执行此操作的正确方法是为集合创建单独的视图模型对象,其中包含int值的属性,以及IsSelected和{{1}的属性} states(因为你最初提到过想要两者)。

这是我之前写的一个例子,只是为了向自己证明通常的方法可以按预期工作。根据您的需要调整它不应该有任何麻烦......

每件商品视图模型:

IsExpanded

窗口的主视图模型:

class TreeItemViewModel : NotifyPropertyChangedBase
{
    public ObservableCollection<TreeItemViewModel> Items { get; }
        = new ObservableCollection<TreeItemViewModel>();

    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set { _UpdateField(ref _isSelected, value, _OnBoolPropertyChanged); }
    }

    private bool _isExpanded;
    public bool IsExpanded
    {
        get { return _isExpanded; }
        set { _UpdateField(ref _isExpanded, value, _OnBoolPropertyChanged); }
    }

    private void _OnBoolPropertyChanged(bool obj)
    {
        _RaisePropertyChanged(nameof(FullText));
    }

    private string _text;
    public string Text
    {
        get { return _text; }
        set { _UpdateField(ref _text, value, _OnTextChanged); }
    }

    private void _OnTextChanged(string obj)
    {
        _RaisePropertyChanged(nameof(FullText));
    }

    public string FullText
    {
        get { return $"{Text} (IsSelected: {IsSelected}, IsExpanded: {IsExpanded})"; }
    }
}

XAML for window:

class MainViewModel : NotifyPropertyChangedBase
{
    public ObservableCollection<TreeItemViewModel> Items { get; }
        = new ObservableCollection<TreeItemViewModel>();

    public ICommand ClearSelection { get; }

    public MainViewModel()
    {
        ClearSelection = new ClearSelectionCommand(this);
    }

    class ClearSelectionCommand : ICommand
    {
        private readonly MainViewModel _parent;

        public ClearSelectionCommand(MainViewModel parent)
        {
            _parent = parent;
        }

#pragma warning disable 67
        public event EventHandler CanExecuteChanged;
#pragma warning restore 67

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public void Execute(object parameter)
        {
            _parent._ClearSelection();
        }
    }

    private void _ClearSelection()
    {
        _ClearSelection(Items);
    }

    private static void _ClearSelection(IEnumerable<TreeItemViewModel> collection)
    {
        foreach (TreeItemViewModel item in collection)
        {
            _ClearSelection(item.Items);
            item.IsSelected = false;
            item.IsExpanded = false;
        }
    }
}

为了完整......

<Window x:Class="TestSO44513864TreeViewIsSelected.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:p="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:l="clr-namespace:TestSO44513864TreeViewIsSelected" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <Window.DataContext> <l:MainViewModel> <l:MainViewModel.Items> <l:TreeItemViewModel Text="One"> <l:TreeItemViewModel.Items> <l:TreeItemViewModel Text="One A"/> <l:TreeItemViewModel Text="One B"/> </l:TreeItemViewModel.Items> </l:TreeItemViewModel> <l:TreeItemViewModel Text="Two"/> <l:TreeItemViewModel Text="Three"/> </l:MainViewModel.Items> </l:MainViewModel> </Window.DataContext> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> </Grid.RowDefinitions> <Button Content="Clear Selection" Command="{Binding ClearSelection}" HorizontalAlignment="Left"/> <TreeView ItemsSource="{Binding Items}" Grid.Row="1"> <TreeView.ItemContainerStyle> <p:Style TargetType="TreeViewItem"> <Setter Property="IsSelected" Value="{Binding IsSelected}"/> <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"/> </p:Style> </TreeView.ItemContainerStyle> <TreeView.ItemTemplate> <HierarchicalDataTemplate DataType="l:TreeItemViewModel" ItemsSource="{Binding Items}"> <TextBlock Text="{Binding FullText}"/> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView> </Grid> </Window> 实施的样板基类:

INotifyPropertyChanged

答案 1 :(得分:-1)

不要在树中的每个节点上使用IsSelected,而是在TreeView本身上使用TreeView.SelectedItem。从这里你可以绑定,但属性是readonly。