[c#wpf选择根项目时出现TreeView问题

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

我在C#中使用WPF TreeView遇到一个奇怪的问题。运行我的应用程序时,我想展开和折叠所选TreeView节点中的所有节点。当我选择根节点时,IsSelected属性不会更新。当我手动展开根节点并单击子节点时,IsSelected属性将更新。问题是,当我使用上下文菜单来展开和折叠根节点上的子节点时,根节点不会被展开。使用上下文菜单后,我展开根节点时,可以看到所有子节点均已正确展开。

我在互联网上进行了很多搜索,但找不到类似的问题。此外,我在C#WPF TreeViews上阅读了很多教程和howtos。到目前为止,我的实现对我而言似乎是正确的,这就是为什么我不理解为什么在单击节点时未设置根属性IsSelected的原因。

有人可以帮助我吗?我已经实现了TreeView,ViewModel和Model如下。在此先感谢

BR

Michael


<TreeView
Grid.Row="1"
Grid.Column="0"
Margin="5"
ContextMenuOpening="FrameworkElement_OnContextMenuOpening"
ItemsSource="{Binding HierarchialTestObjects}"
SelectedItemChanged="TreeView_OnSelectedItemChanged">
<TreeView.ItemTemplate>
    <HierarchicalDataTemplate DataType="{x:Type vm:HierarchialTestObjectViewModel}" ItemsSource="{Binding Childs}">
        <HierarchicalDataTemplate.ItemContainerStyle>
            <Style TargetType="{x:Type TreeViewItem}">
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
                <Setter Property="IsExpanded" Value="{Binding Path=IsExpanded, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
            </Style>
        </HierarchicalDataTemplate.ItemContainerStyle>
        <StackPanel Orientation="Horizontal">
            <Label Content="{Binding Path=Name}" />
        </StackPanel>
    </HierarchicalDataTemplate>
</TreeView.ItemTemplate>
<TreeView.ContextMenu>
    <ContextMenu>
        <MenuItem Command="{Binding ExpandAllTreeItemsCommand}" Header="Expand All" />
        <MenuItem Command="{Binding CollapseAllTreeItemsCommand}" Header="Collapse All" />
    </ContextMenu>
</TreeView.ContextMenu>

namespace mynamespace.subspace.report.data
{
// ... usings removed

public class HierarchialTestObject
{
    public string Name { get; set; }

    public List<HierarchialTestObject> Childs { get; set; } = new List<HierarchialTestObject>();

    public List<string> Path { get; set; } = new List<string>();

    public List<string> ParentPath => Path?.AsEnumerable()?.Reverse()?.Skip(1)?.Reverse()?.ToList();

    public IHierarchialItem Item { get; set; }

    public HierarchialTestObject(IHierarchialItem item)
    {
        Item = item;
        Name = item.ShortDescription;
    }

    public void SetChilds(IEnumerable<IHierarchialItem> childs)
    {
        childs.ToList().ForEach(c => Childs?.Add(new HierarchialTestObject(c)));
    }
}
}

ViewModel

namespace mynamespace.subspace.report.viewmodel
{
// ... usings removed

public class HierarchialTestObjectViewModel : ViewModelBase
{
    public delegate void NotifyTreeItemSelected(HierarchialTestObjectViewModel item);

    public event NotifyTreeItemSelected OnTreeItemSelected;

    private bool _isSelected;
    public bool IsSelected
    {
        get { return _isSelected; }
        set
        {
            if (_isSelected != value)
            {
                SetProperty(ref _isSelected, value, nameof(IsSelected));
                if (value)
                {
                    // this is a hack-ish workaround because i cannot use PRISM or other similar libs
                    OnTreeItemSelected?.Invoke(this);
                }
            }
        }
    }

    private bool _isExpanded;
    public bool IsExpanded
    {
        get { return _isExpanded; }
        set
        {
            if (_isExpanded != value)
            {
                SetProperty(ref _isExpanded, value, nameof(IsExpanded));
                RaisePropertyChanged(nameof(IconType));
            }
        }
    }



    private string _name;
    public string Name
    {
        get { return _name; }
        set
        {
            if (_name != value)
            {
                SetProperty(ref _name, value, nameof(Name));
            }
        }
    }



    private IHierarchialItem _item;
    public IHierarchialItem Item
    {
        get { return _item; }
        set
        {
            if (_item != value)
            {
                SetProperty(ref _item, value, nameof(Item));
            }
        }
    }


    private List<string> _path;
    public List<string> Path
    {
        get { return _path; }
        set
        {
            if (_path != value)
            {
                SetProperty(ref _path, value, nameof(Path));
            }
        }
    }

    private ObservableCollection<HierarchialTestObjectViewModel> _childs;
    public ObservableCollection<HierarchialTestObjectViewModel> Childs
    {
        get { return _childs; }
        set
        {
            if (_childs != value)
            {
                SetProperty(ref _childs, value, nameof(Childs));
            }
        }
    }

    public HierarchialTestObjectViewModel(HierarchialTestObject obj)
    {
        var childs = obj.Childs.Select(c => new HierarchialTestObjectViewModel(c)).ToList();
        Path = obj.Path ?? new List<string>();
        Childs = new ObservableCollection<HierarchialTestObjectViewModel>(childs);
        Item = obj.Item;
        Name = obj.Name;
    }

    public void ExpandRecursively()
    {
        IsExpanded = true;
        Childs?.ToList().ForEach(c => c.ExpandRecursively());
    }

    public void CollapseRecursively()
    {
        IsExpanded = false;
        Childs?.ToList().ForEach(c => c.CollapseRecursively());
    }

}
}
c# wpf treeview
1个回答
0
投票

问题是您从未设置根项目的ItemContainerStyle。仅用于子项。因此,根数据模型的IsExpandedIsSelected属性未连接到TreeViewItem数据容器。

只需设置TreeView.ItemContainerStyle即可解决问题:

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

备注

[TreeViewItem.IsSelected默认绑定BindingMode.TwoWay。默认情况下,TreeViewItem.IsSelectedTreeViewItem.IsSelectedUpdateSourceTrigger设置为PropertyChanged。这样,您可以减少代码并提高可读性。

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