WPF在失去焦点时刷新TreeView

时间:2010-07-13 17:15:09

标签: wpf layout treeview refresh

由于我对帖子所做的更改,我认为要打开另一个帖子。在新的帖子中,我发布了我的(provvisory)解决方案。 你可以找到它here

嗨! 我在WPF应用程序(Framework 3.5 SP1)中遇到了TreeView问题。 这是一个拥有2个数据级别的TreeVIew。我以特定方式展开/折叠第一级的项目(只需在TreeViewItem上单击鼠标)。再次当我展开第一级TreeViewItem时,我将一些二级TreeViewItem添加到组中(这是一个重要的细节,事实上,如果我不添加项目,则问题不会发生)。一切正常,直到TreeView失去焦点。 例如,如果我在第一个位置展开TreeViewItem,同时将一个元素添加到第二个级别,那么我单击一个按钮(让TreeView失去焦点),然后再次单击TreeViewItem在第三个位置展开它,由鼠标位置命中测试得到的TreeViewItem不是“真正的”TreeViewItem(在本例中是第三个),而是一个位于比单击的位置更高的TreeViewItem (在这种情况下是第二个)。 我试图在TreeView-LostFocus事件上使用UpdateLayout方法,但没有结果。可能我需要一个相反的方法:从UI开始,刷新包含TreeViewItems位置的对象。 你能帮我么? 谢谢! Pileggi

这是代码:

   ' in this way I tried to put remedy at the problem, but it doesn't work.
    Private Sub tvArt_LostFocus(ByVal sender As Object, ByVal e As RoutedEventArgs) Handles tvArt.LostFocus
        Me.tvArt.UpdateLayout()

        e.Handled = True
    End Sub

    ' here I expand / collapse the items of the first level of my TreeView
    Private Sub tvArt_PreviewMouseUp(ByVal sender As System.Object, ByVal e As MouseButtonEventArgs) Handles tvArt.PreviewMouseUp
        Dim p As Point = Nothing
        Dim tvi As TreeViewItem = getItemFromMousePosition(Of TreeViewItem)(p, e.OriginalSource, Me.tvArt)
        If tvi Is Nothing = False Then
            If tvi.HasItems Then
                Dim be As BindingExpression = BindingOperations.GetBindingExpression(tvi, TreeViewItem.ItemsSourceProperty)
                Dim ri As P_RicambiItem = DirectCast(be.DataItem, P_RicambiItem)
                If ri.isExpanded = False then
                    ' here I add items to the second level collection
                End If
                ri.isExpanded = Not ri.isExpanded
            End If
        End If

        e.Handled = True
    End Sub

    Private Function getItemFromMousePosition(Of childItem As DependencyObject)(ByRef p As Point, ByVal sender As UIElement, _
        ByVal _item As UIElement) As childItem

        p = sender.TranslatePoint(New Point(0, 0), _item)
        Dim obj As DependencyObject = DirectCast(_item.InputHitTest(p), DependencyObject)
        While obj Is Nothing = False AndAlso TypeOf obj Is childItem = False
            obj = VisualTreeHelper.GetParent(obj)
        End While
        Return DirectCast(obj, childItem)
    End Function

3 个答案:

答案 0 :(得分:0)

你的热门测试代码似乎有些奇怪。您忽略MouseButtonEventArgs对象给出的鼠标位置,然后在TreeView中针对单击的控件的左上角执行命中测试。这通常会再次给你相同的控制,我怀疑你的怪异行为是在没有的情况下。而不是做TranslatePoint和InputHitTest,只需直接使用发件人。您的帮助函数简化为:

Private Function getParentOfType(Of childItem As DependencyObject)(ByVal sender As UIElement) As childItem
    Dim obj As DependencyObject = sender
    While obj Is Nothing = False AndAlso TypeOf obj Is childItem = False
        obj = VisualTreeHelper.GetParent(obj)
    End While
    Return DirectCast(obj, childItem)
End Function

通过利用MouseUp是路由事件并让它为您找到TreeViewItem父级这一事实,您实际上可以再次使其更简单。不是将事件处理程序添加到TreeView本身,而是将一个MouseUp处理程序添加到TreeViewItem,并且它将始终与TreeViewItem的发送者一起调用。

您还应该将IsExpanded上的绑定设置为双向(如果尚未绑定)。这样,您可以在TreeViewItem上更新IsExpanded,并将值推送到绑定源。

在XAML中:

<TreeView.ItemContainerStyle>
    <Style TargetType="{x:Type TreeViewItem}">
        <Setter Property="IsExpanded" Value="{Binding isExpanded, Mode=TwoWay}" />
        <EventSetter Event="Mouse.MouseUp" Handler="tvi_MouseUp"/>
    </Style>
</TreeView.ItemContainerStyle>

然后在代码中:

Private Sub tvi_MouseUp(ByVal sender As System.Object, ByVal e As MouseButtonEventArgs)
    Dim tvi As TreeViewItem = DirectCast(sender, TreeViewItem)
    If tvi.HasItems Then
        tvi.IsExpanded = Not tvi.IsExpanded
    End If
    e.Handled = True
End Sub

答案 1 :(得分:0)

谢谢你,你很善良。但不幸的是,问题与您的解决方案相同。 我省略了一个重要的细节(对不起):当我展开第一级TreeViewItem时,我添加了一些二级TreeviewItems。这会导致问题,如果我不添加项目一切正常。 我编辑了我的问题,使其更易于理解。 也许现在解决方案更容易(我希望)。 谢谢, Pileggi

答案 2 :(得分:0)

由于我对帖子所做的更改,我认为要打开另一个帖子。在新的帖子中,我发布了我的(provvisory)解决方案。你可以找到它here