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 尚未完成。这是一个丑陋的解决方法,但对我有用...
我有一个树视图,其中有可选择的项目,以及可能触发某些代码操作的子项目。单击子项时,应执行操作,但父项必须 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 尚未完成。这是一个丑陋的解决方法,但对我有用...