WPF 在树视图中操作选定项

WPF manipulate selected item in treeview

我有一个树视图,其中有可选择的项目,以及可能触发某些代码操作的子项目。单击子项时,应执行操作,但父项必须 remain/become 选定项。

我面临的问题是项目没有被正确取消选择,导致在树视图中选择了多个项目。

这是树视图的 xaml:

    <TreeView Name="Treeview1" Style="{StaticResource vcc_Treeview}" >
        <TreeView.ItemTemplate >
            <HierarchicalDataTemplate ItemsSource="{Binding Children}" >
                <StackPanel Orientation="Horizontal">
                    <Image Source="{Binding ImgSrc}" Style="{StaticResource vcc_TreeviewItemImage}" />
                    <TextBlock Text="{Binding Description}" Style="{StaticResource vcc_TreeviewItemTextblock}" Foreground="{Binding TextColorBrush}" />
                </StackPanel>
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
        <TreeView.ItemContainerStyle>
            <Style TargetType="TreeViewItem">
                <Setter Property="IsSelected" Value="{Binding Path=IsSelected, Mode=TwoWay, Converter={StaticResource clsBindingDebugger}}" />
            </Style>
        </TreeView.ItemContainerStyle>
    </TreeView>

clsBindingDebugger 除了调试打印转换后的值并传递 convert- 和 convertback 值外什么都不做。

接下来是略微缩短的 TreeviewItem Class

Public Class MyTreeviewItem
Implements INotifyPropertyChanged

Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged

Public Event MyTreeviewItem_ExpandedChanged(MTI As MyTreeviewItem, IsExpanded As Boolean)
Public Event MyTreeviewItem_SelectedChanged(MTI As MyTreeviewItem, IsSelected As Boolean)



Public Sub New(Optional Level_ As Integer = 1, Optional ByVal Key_ As String = "")
    MyBase.New()
    Me.Children = New ObservableCollection(Of MyTreeviewItem)
    _Key = Key_
    _Level = Level_
End Sub

Private _Level As Integer
Public Property Level As Integer
    Get
        Level = _Level
    End Get
    Set(value As Integer)
        _Level = value
    End Set
End Property

Private _Descr As String = ""
Public Property Description As String
    Get
        Description = _Descr
    End Get
    Set(value As String)
        _Descr = value
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Description"))
    End Set
End Property

Private _Key As String = ""
Public Property Key As String
    Get
        Key = _Key
    End Get
    Set(value As String)
        _Key = value
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Key"))
    End Set
End Property

Private _ImgSrc As ImageSource
Public Property ImgSrc As ImageSource
    Get
        ImgSrc = _ImgSrc
    End Get
    Set(value As ImageSource)
        _ImgSrc = value
    End Set
End Property

Private _Children As ObservableCollection(Of MyTreeviewItem)
Public Property Children As ObservableCollection(Of MyTreeviewItem)
    Get
        Return _Children
    End Get
    Set(value As ObservableCollection(Of MyTreeviewItem))
        _Children = value
    End Set
End Property

Private _IsSelected As Boolean
Overloads Property IsSelected As Boolean
    Get
        Return _IsSelected
    End Get
    Set(ByVal value As Boolean)
        _IsSelected = value
        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("IsSelected"))
        RaiseEvent MyTreeviewItem_SelectedChanged(Me, _IsSelected)
    End Set
End Property

Private _IsActionItem As Boolean
Overloads Property IsActionItem As Boolean
    Get
        Return _IsActionItem
    End Get
    Set(ByVal value As Boolean)
        _IsActionItem = value
    End Set
End Property
End Class

终于触发了事件MyTreeviewItem_SelectedChanged:

Private ReselectingParent As Boolean = False

Private Sub MyTreeviewItem_SelectedChanged(MTI As MyTreeviewItem, IsSelected As Boolean)
Debug.Print(MTI.Description & "  Selected = " & IsSelected)
If ReselectingParent Then Exit Sub

If IsSelected Then

    'Do some (action) stuff here

    If MTI.IsActionItem AndAlso MTI.Parent IsNot Nothing Then
        ReselectingParent = True 'to prevent this sub from being executed with the next 2 lines
        MTI.IsSelected = False
        MTI.Parent.IsSelected = True
        ReselectingParent = False
    End If
End If
End Sub

假设树视图如下所示:

item 1
--Action 1
--Action 2
Item 2
--Action 3
--Action 4

在我的初始情况下,选择了项目 2。现在我单击操作 1,因此应该执行操作,然后项目 1 应该是选定的项目。 debug.print 结果如下:

ConvertBack: False
Item 2  Selected = False
Convert: False
ConvertBack: True
Action 2  Selected = True
Action 2  Selected = False
Convert: True
Item 1  Selected = True
Convert: False

此时项目 1 已被选中,这是应该的。 现在我点击操作 3。

ConvertBack: False
Action 2  Selected = False
Convert: False
ConvertBack: True
Action 3  Selected = True
Action 3  Selected = False
Convert: True
Item 2  Selected = True
Convert: False

结果是Item 1和Item 2都被选中了,应该只选中Item 2。第二个调试器块说 "Action 2 Selected = False",这应该是 "Item 1 Selected = False"

希望我说清楚了。谁能指出我的问题的解决方案? 谢谢!

谁感兴趣...

我还是不太明白为什么代码不能正常工作。但显然点击的操作项没有正确删除select。而不是调用这些行:

    ReselectingParent = True 'to prevent this sub from being executed with the next 2 lines
    MTI.IsSelected = False
    MTI.Parent.IsSelected = True
    ReselectingParent = False

直接在 MyTreeviewItem_SelectedChanged 我现在改为调用计时器。在 timer_elapsed 事件中,我调用了四行。 显然,在将代码调用到其父项 select 时,操作项的主要 select 尚未完成。这是一个丑陋的解决方法,但对我有用...