none
Treeview control (March 2009) I guess a bug...

    Question

  •  

     Hi,

    I have a treeview which contains only a root node and a child of it.Steps to reproduce the behavior:

    1. Expand the root node and select the child of it, selection changed event is raised as expected.

    2. When the child is selected collapse the root node. The selected index changed event is fired and the root node is automatically selected.

    I guess that should be a bug...

     

     
                    <controls:TreeView x:Name="tree" Margin="5" Background="White" SelectedItemChanged="tree_SelectedItemChanged"
    BorderBrush="Black" BorderThickness="0.3" Canvas.ZIndex="0"
    FontSize="10" Foreground="Red" Width="400" Height="400">
    <controls:TreeViewItem Header="GENEL MÜDÜRLÜK" Tag="1000000000000" />
    </controls:TreeView>

      
            Dim parentNode As New TreeViewItem
            parentNode = tree.Items(0)
            Dim dummyNode As New TreeViewItem
            dummyNode.Header = "dummyNode"
            parentNode.Items.Add(dummyNode)
     
     
        Private Sub tree_SelectedItemChanged(ByVal sender As System.Object, _
    ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of System.Object))
    Dim t As TreeViewItem = tree.SelectedItem
    End Sub
     
      
    Friday, March 20, 2009 5:16 AM

Answers

  • Hi,

    Thanks for the detailed user scenario!

    So, from your last line, I understand you need a TreeView that throws a LeftMouseButtonDown event when a TreeViewItem is clicked?

    We don't support throwing LeftMouseButtonDown events due to compatibility issues with WPF (WPF TreeView doesn't do that and we want to make sure you can use your code on WPF).

    However, if you really want to, you can just inherit from our TreeView and expose the event yourself.

    We'll start by creating a custom TreeView and TreeViewItem.

     

        public class LeftMouseButtonDownTreeView : TreeView

        {

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

        }

    Than make sure both TreeView and TreeViewItem generate children of the new TreeViewItem.

        public class LeftMouseButtonDownTreeView : TreeView

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

        }

    Next, we'll expose a property on the new TreeViewItem that points back to the TreeView.

        public class LeftMouseButtonDownTreeView : TreeView

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            public LeftMouseButtonDownTreeView ParentTreeView { get; set; }

        }

     We'll make sure to populate that property.

        public class LeftMouseButtonDownTreeView : TreeView

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

            {

                if (IsItemItsOwnContainerOverride(element))

                {

                    LeftMouseButtonDownTreeViewItem treeViewItem = (LeftMouseButtonDownTreeViewItem) element;

                    treeViewItem.ParentTreeView = this;

                }

                base.PrepareContainerForItemOverride(element, item);

            }

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

            {

                if (IsItemItsOwnContainerOverride(element))

                {

                    LeftMouseButtonDownTreeViewItem treeViewItem = (LeftMouseButtonDownTreeViewItem)element;

                    treeViewItem.ParentTreeView = this.ParentTreeView;

                }

                base.PrepareContainerForItemOverride(element, item);

            }

     

            public LeftMouseButtonDownTreeView ParentTreeView { get; set; }

        }

    We'll expose a new event called "TreeViewItemMouseLeftButtonDown" from the TreeView.
    Additionally, we'll expose a method to invoke the event.

        public class LeftMouseButtonDownTreeView : TreeView

        {

     

            ...

     

            public event MouseButtonEventHandler TreeViewItemMouseLeftButtonDown;

     

            internal void InvokeTreeViewItemMouseLeftButtonDown(MouseButtonEventArgs e)

            {

                MouseButtonEventHandler Handler = TreeViewItemMouseLeftButtonDown;

                if (Handler != null)

                    Handler(this, e);

            }

        }

    And make sure to invoke this event whenever a TreeViewItem is clicked.

        public class LeftMouseButtonDownTreeView : TreeView

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

            {

                if (IsItemItsOwnContainerOverride(element))

                {

                    LeftMouseButtonDownTreeViewItem treeViewItem = (LeftMouseButtonDownTreeViewItem) element;

                    treeViewItem.ParentTreeView = this;

                }

                base.PrepareContainerForItemOverride(element, item);

            }

     

            public event MouseButtonEventHandler TreeViewItemMouseLeftButtonDown;

     

            internal void InvokeTreeViewItemMouseLeftButtonDown(MouseButtonEventArgs e)

            {

                MouseButtonEventHandler Handler = TreeViewItemMouseLeftButtonDown;

                if (Handler != null)

                    Handler(this, e);

            }

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

            {

                if (IsItemItsOwnContainerOverride(element))

                {

                    LeftMouseButtonDownTreeViewItem treeViewItem = (LeftMouseButtonDownTreeViewItem)element;

                    treeViewItem.ParentTreeView = this.ParentTreeView;

                }

                base.PrepareContainerForItemOverride(element, item);

            }

     

            public LeftMouseButtonDownTreeView ParentTreeView { get; set; }

     

            protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)

            {

                base.OnMouseLeftButtonDown(e);

                ParentTreeView.InvokeTreeViewItemMouseLeftButtonDown(e);

            }

        }

    And here's a quick usage sample:

            <Grid.Resources>

                <common:HierarchicalDataTemplate x:Key="myHierarchicalTemplate" ItemsSource="{Binding Items}" >

                    <TextBlock Text="{Binding myString}" />

                </common:HierarchicalDataTemplate>

            </Grid.Resources>

            <SL_40307_VS:LeftMouseButtonDownTreeView x:Name="trv" ItemTemplate="{StaticResource myHierarchicalTemplate}" />

        {

            public SilverlightControl7()

            {

                InitializeComponent();

                trv.ItemsSource = new ObservableCollection<myItem>()

                                      {

                                          new myItem("Hello",

                                              new myItem("World"),

                                              new myItem("Foo"),

                                              new myItem("Bar")),

                                          new myItem("Moo",

                                              new myItem("Boo",

                                                new myItem("Goo"))),

                                      };

     

                trv.TreeViewItemMouseLeftButtonDown += new MouseButtonEventHandler(trv_TreeViewItemMouseLeftButtonDown);

            }

     

            private void trv_TreeViewItemMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

            {

            }

     The new TreeViewItemMouseLeftButtonDown event will be called whenever a TreeViewItem is clicked.

     

     

     

     

     

    Monday, March 23, 2009 5:23 PM

All replies

  • This has always been a problem with the TreeView control...  Sad

    ... and it is a bit confusing for the users and annoying to us as developers.

    Friday, March 20, 2009 12:36 PM
  • Hi,

    Just to re-iterate what you're seeing: If a TreeViewItem is collapsed and the currently selected TreeViewITem is nested in it than the containing TreeViewItem will be selected.

    That is the correct behavior for TreeView. As such it's also compatible with the behavior for the WPF TreeView.

    Why do you think this is a bug?

    From a user's perspective collapsing a TreeViewItem that contains the selected TreeViewItem is equivalent to selecting the current TreeViewItem.

    If you'd like to change that behavior I guess you can catch the SelectedItemChanged event and reselect the hidde item.
    Though, that would be quite confusing for users. For a user, if they can't visually see a TreeViewItem is selected than it's not.

    Sincerely,

    Friday, March 20, 2009 10:14 PM
  • Hi,

    Just to re-iterate what you're seeing: If a TreeViewItem is collapsed and the currently selected TreeViewITem is nested in it than the containing TreeViewItem will be selected.

    That is the correct behavior for TreeView. As such it's also compatible with the behavior for the WPF TreeView.

    Why do you think this is a bug?

    From a user's perspective collapsing a TreeViewItem that contains the selected TreeViewItem is equivalent to selecting the current TreeViewItem.

    If you'd like to change that behavior I guess you can catch the SelectedItemChanged event and reselect the hidde item.
    Though, that would be quite confusing for users. For a user, if they can't visually see a TreeViewItem is selected than it's not.

    Sincerely,

     

     

    Hi Justin, thanks for the information. In my application the treeview is nested in an aspx page and it stores some hierachical data related to the departments in my company. (I paste all the code below) Let me explain what I am trying to do:

     When the user selects an item from the treeview an ajax popup window is opened containing the people who works for that department (passing parameters by hidden fields, updating the hidden field's region by calling a javascript function from silverlight, then showing the popup in the hiddenfield's onvaluechanged event in aspx codebehind). So when a user selects a node and then collapses its parent node the popup window is again opened despite the user does not want that to happen.

     

    However, I managed that according to my needs.  In the treeview selectedItemChanged event  I set the selected item's isSelected property to false. (of course after I set the hidden field's value and invoking the javascript function to update the region) . None of the nodes is seen as selected but user will always know which item he selected because the header of the popup window shows that.

     

    Now my problem is: The user clicks an item and the popup is shown, when the user closes the popup and again clicks to the same item the event is not fired so the popup is not opened... Please look at the following line carefully after examining the code:

    ------------'HiddenFieldSL.Value = "XXX" ' PLEASE TRY AGAIN AFTER UNCOMMENTING THIS LINE-----------
     
    When I try by uncommenting that line of code a very strange thing happens: 
    When the first time the treeview is loaded I tried to expand the root node
    everything is fine, selectedItemchanged event does not get fired, BUT when I click
    on a node and then try to expand and collapse the node each time
    selectedItemchanged event is fired and this is the point everthing gets messed up.
    Please am I missing something? Is there a logical mistake or something please help...
     The post is quite long, sorry for that but I wanted everything to be clearly explained... 

     Treeview declaration in page.xaml:

                    <controls:TreeView x:Name="tree" Margin="5" Background="White" 
    BorderBrush="Black" BorderThickness="0.3" Canvas.ZIndex="0"
    FontSize="10" Foreground="Red" Width="400" Height="400"
    SelectedItemChanged="tree_SelectedItemChanged">
    <controls:TreeViewItem Header="ROOT NODE" Tag="1000000000000" />
    </controls:TreeView>

      

    Page.xaml.vb:

     Public Sub New()
    InitializeComponent()
    AddHandler Loaded, AddressOf Page_Loaded
    End Sub

    Private Sub
    Page_Loaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
    parentNode = tree.Items(0)
    Dim dummyNode As New TreeViewItem
    dummyNode.Header = "CHILD NODE"
    dummyNode.Tag = "1000"
    parentNode.Items.Add(dummyNode)
    End Sub

    Private Sub
    tree_SelectedItemChanged(ByVal sender As System.Object, _
    ByVal e As System.Windows.RoutedPropertyChangedEventArgs(Of System.Object))
    Dim t As New TreeViewItem
    t = tree.SelectedItem

    If Not t Is Nothing Then
    Document.GetElementById("HiddenFieldSL").SetAttribute("value", t.Tag.ToString)
    System.Windows.Browser.HtmlPage.Window.Invoke("updateRegion")
    t.IsSelected = False
    End If
    End Sub
     
    Default.aspx:

    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
    <title></title>
    <script type="text/javascript" language="javascript">
    function updateRegion() {
    var prm = Sys.WebForms.PageRequestManager.getInstance();
    prm._doPostBack('HiddenFieldSL', '');
    }
    </script>
    </head>
    <body>
    <form id="form1" runat="server" style="height:100%;">
    <asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
    <asp:HiddenField ID="HiddenFieldSL" runat="server" Value="X"
    OnValueChanged="HiddenFieldSL_OnValueChanged" />
    </ContentTemplate>
    </asp:UpdatePanel>

    <div style="height:100%;" id="SLobject" runat="server">
    <asp:Silverlight ID="Xaml1" runat="server" Source="~/ClientBin/CPtreeview.xap"
    MinimumVersion="2.0.31005.0" Width="410px" Height="410px" />
    </div>
    <asp:GridView ID="GridView1" runat="server"/>
    </form>
    </body>
    </html>
     
    Default.aspx.vb:
        Protected Sub HiddenFieldSL_OnValueChanged(ByVal sender As Object, _
    ByVal e As System.EventArgs) Handles HiddenFieldSL.ValueChanged
    Dim dsBolumTree As New dsHiyerarsiTableAdapters.dtHiyerarsiTableAdapter
    Dim dtBolumTree As DataTable = dsBolumTree.GetData(HiddenFieldSL.Value)
    GridView1.DataSource = dtBolumTree
    GridView1.DataBind()

    'HiddenFieldSL.Value = "XXX" ' PLEASE TRY AGAIN AFTER UNCOMMENTING THIS LINE
    End Sub
     

     

     

    Monday, March 23, 2009 4:43 AM
  • Hi,

    Thanks for the detailed user scenario!

    So, from your last line, I understand you need a TreeView that throws a LeftMouseButtonDown event when a TreeViewItem is clicked?

    We don't support throwing LeftMouseButtonDown events due to compatibility issues with WPF (WPF TreeView doesn't do that and we want to make sure you can use your code on WPF).

    However, if you really want to, you can just inherit from our TreeView and expose the event yourself.

    We'll start by creating a custom TreeView and TreeViewItem.

     

        public class LeftMouseButtonDownTreeView : TreeView

        {

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

        }

    Than make sure both TreeView and TreeViewItem generate children of the new TreeViewItem.

        public class LeftMouseButtonDownTreeView : TreeView

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

        }

    Next, we'll expose a property on the new TreeViewItem that points back to the TreeView.

        public class LeftMouseButtonDownTreeView : TreeView

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            public LeftMouseButtonDownTreeView ParentTreeView { get; set; }

        }

     We'll make sure to populate that property.

        public class LeftMouseButtonDownTreeView : TreeView

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

            {

                if (IsItemItsOwnContainerOverride(element))

                {

                    LeftMouseButtonDownTreeViewItem treeViewItem = (LeftMouseButtonDownTreeViewItem) element;

                    treeViewItem.ParentTreeView = this;

                }

                base.PrepareContainerForItemOverride(element, item);

            }

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

            {

                if (IsItemItsOwnContainerOverride(element))

                {

                    LeftMouseButtonDownTreeViewItem treeViewItem = (LeftMouseButtonDownTreeViewItem)element;

                    treeViewItem.ParentTreeView = this.ParentTreeView;

                }

                base.PrepareContainerForItemOverride(element, item);

            }

     

            public LeftMouseButtonDownTreeView ParentTreeView { get; set; }

        }

    We'll expose a new event called "TreeViewItemMouseLeftButtonDown" from the TreeView.
    Additionally, we'll expose a method to invoke the event.

        public class LeftMouseButtonDownTreeView : TreeView

        {

     

            ...

     

            public event MouseButtonEventHandler TreeViewItemMouseLeftButtonDown;

     

            internal void InvokeTreeViewItemMouseLeftButtonDown(MouseButtonEventArgs e)

            {

                MouseButtonEventHandler Handler = TreeViewItemMouseLeftButtonDown;

                if (Handler != null)

                    Handler(this, e);

            }

        }

    And make sure to invoke this event whenever a TreeViewItem is clicked.

        public class LeftMouseButtonDownTreeView : TreeView

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

            {

                if (IsItemItsOwnContainerOverride(element))

                {

                    LeftMouseButtonDownTreeViewItem treeViewItem = (LeftMouseButtonDownTreeViewItem) element;

                    treeViewItem.ParentTreeView = this;

                }

                base.PrepareContainerForItemOverride(element, item);

            }

     

            public event MouseButtonEventHandler TreeViewItemMouseLeftButtonDown;

     

            internal void InvokeTreeViewItemMouseLeftButtonDown(MouseButtonEventArgs e)

            {

                MouseButtonEventHandler Handler = TreeViewItemMouseLeftButtonDown;

                if (Handler != null)

                    Handler(this, e);

            }

        }

     

        public class LeftMouseButtonDownTreeViewItem : TreeViewItem

        {

            protected override DependencyObject GetContainerForItemOverride()

            {

                return new LeftMouseButtonDownTreeViewItem();

            }

     

            protected override bool IsItemItsOwnContainerOverride(object item)

            {

                return item is LeftMouseButtonDownTreeViewItem;

            }

     

            protected override void PrepareContainerForItemOverride(DependencyObject element, object item)

            {

                if (IsItemItsOwnContainerOverride(element))

                {

                    LeftMouseButtonDownTreeViewItem treeViewItem = (LeftMouseButtonDownTreeViewItem)element;

                    treeViewItem.ParentTreeView = this.ParentTreeView;

                }

                base.PrepareContainerForItemOverride(element, item);

            }

     

            public LeftMouseButtonDownTreeView ParentTreeView { get; set; }

     

            protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)

            {

                base.OnMouseLeftButtonDown(e);

                ParentTreeView.InvokeTreeViewItemMouseLeftButtonDown(e);

            }

        }

    And here's a quick usage sample:

            <Grid.Resources>

                <common:HierarchicalDataTemplate x:Key="myHierarchicalTemplate" ItemsSource="{Binding Items}" >

                    <TextBlock Text="{Binding myString}" />

                </common:HierarchicalDataTemplate>

            </Grid.Resources>

            <SL_40307_VS:LeftMouseButtonDownTreeView x:Name="trv" ItemTemplate="{StaticResource myHierarchicalTemplate}" />

        {

            public SilverlightControl7()

            {

                InitializeComponent();

                trv.ItemsSource = new ObservableCollection<myItem>()

                                      {

                                          new myItem("Hello",

                                              new myItem("World"),

                                              new myItem("Foo"),

                                              new myItem("Bar")),

                                          new myItem("Moo",

                                              new myItem("Boo",

                                                new myItem("Goo"))),

                                      };

     

                trv.TreeViewItemMouseLeftButtonDown += new MouseButtonEventHandler(trv_TreeViewItemMouseLeftButtonDown);

            }

     

            private void trv_TreeViewItemMouseLeftButtonDown(object sender, MouseButtonEventArgs e)

            {

            }

     The new TreeViewItemMouseLeftButtonDown event will be called whenever a TreeViewItem is clicked.

     

     

     

     

     

    Monday, March 23, 2009 5:23 PM
  •  Hi, Justin thank you so much for your help, I finally succeeded what I want, I will make some more tests but I think there would not be a problem from now on.

    Now, I have one more question to you: I took your code and converted it to vb code in order to use it in my application. After conversion in one section the code gave an error here is that section:

     

            public event MouseButtonEventHandler TreeViewItemMouseLeftButtonDown;

    internal void InvokeTreeViewItemMouseLeftButtonDown(MouseButtonEventArgs e)
    {
    MouseButtonEventHandler Handler = TreeViewItemMouseLeftButtonDown;
    if (Handler != null)
    Handler(this, e);
    }

      Its Vb equivalent is below after conversion:

    Public Event TreeViewItemMouseLeftButtonDown As MouseButtonEventHandler

    Friend Sub InvokeTreeViewItemMouseLeftButtonDown(ByVal e As MouseButtonEventArgs)
    Dim Handler As MouseButtonEventHandler = TreeViewItemMouseLeftButtonDown
    RaiseEvent Handler(Me, e)
    End Sub
     The error says:
    "TreeViewItemMouseLeftButtonDown is an event and cannot be called directly. 
    Use a 'RaiseEvent' statement to raise an event."
     Then I modified the code as below:
     
        Friend Sub InvokeTreeViewItemMouseLeftButtonDown(ByVal e As MouseButtonEventArgs)
    'Dim Handler As MouseButtonEventHandler = TreeViewItemMouseLeftButtonDown ' REMOVED
    RaiseEvent TreeViewItemMouseLeftButtonDown(Me, e)
    End Sub



    Now everthing is okey the code works fine. Why you did one more assignment in your code I could not figure out,
     not sure have you tested that code or not. If yes why did it gave error in vb?
     By the way is it necessary to check if the handler is null or not?  I am not code expert so want to learn...
    That section is the one confused me, if you can explain me I will appreciate.
    By the way I am pasting the vb equivalent of the entire code so people searching
     for the same implementation will have both code samples.

    One more thing to mention: In your example code the sender object is the treeview itself, I modified it so now the sender object is the treeviewitem itself.

    Sincerely...

     

    Public Class LeftMouseButtonDownTreeView
    Inherits TreeView

    Protected Overloads Overrides Function GetContainerForItemOverride() As DependencyObject
    Return New LeftMouseButtonDownTreeViewItem
    End Function

    Protected Overloads Overrides Function
    IsItemItsOwnContainerOverride( _
    ByVal item As Object) As Boolean
    Return TypeOf
    item Is LeftMouseButtonDownTreeViewItem
    End Function

    Protected Overloads Overrides Sub
    PrepareContainerForItemOverride( _
    ByVal element As DependencyObject, ByVal item As Object)
    If IsItemItsOwnContainerOverride(element) Then
    Dim
    treeViewItem As LeftMouseButtonDownTreeViewItem = _
    DirectCast(element, LeftMouseButtonDownTreeViewItem)
    treeViewItem.ParentTreeView = Me
    End If
    MyBase
    .PrepareContainerForItemOverride(element, item)
    End Sub

    Public Event
    TreeViewItemMouseLeftButtonDown As MouseButtonEventHandler

    Friend Sub InvokeTreeViewItemMouseLeftButtonDown(ByVal item As Object, _
    ByVal e As MouseButtonEventArgs)
    RaiseEvent TreeViewItemMouseLeftButtonDown(item, e)
    End Sub
    End Class

    Public Class
    LeftMouseButtonDownTreeViewItem
    Inherits TreeViewItem

    Protected Overloads Overrides Function GetContainerForItemOverride() As DependencyObject
    Return New LeftMouseButtonDownTreeViewItem()
    End Function

    Protected Overloads Overrides Function
    IsItemItsOwnContainerOverride( _
    ByVal item As Object) As Boolean
    Return TypeOf
    item Is LeftMouseButtonDownTreeViewItem
    End Function

    Protected Overloads Overrides Sub
    PrepareContainerForItemOverride( _
    ByVal element As DependencyObject, ByVal item As Object)
    If IsItemItsOwnContainerOverride(element) Then
    Dim
    treeViewItem As LeftMouseButtonDownTreeViewItem = _
    DirectCast(element, LeftMouseButtonDownTreeViewItem)
    treeViewItem.ParentTreeView = Me.ParentTreeView
    End If
    MyBase
    .PrepareContainerForItemOverride(element, item)
    End Sub

    Private
    _ParentTreeView As LeftMouseButtonDownTreeView

    Public Property ParentTreeView() As LeftMouseButtonDownTreeView
    Get
    Return
    _ParentTreeView
    End Get
    Set
    (ByVal value As LeftMouseButtonDownTreeView)
    _ParentTreeView = value
    End Set
    End Property

    Protected Overloads Overrides Sub
    OnMouseLeftButtonDown(ByVal e As MouseButtonEventArgs)
    MyBase.OnMouseLeftButtonDown(e)
    ParentTreeView.InvokeTreeViewItemMouseLeftButtonDown(Me, e)
    End Sub
    End Class
     
    Tuesday, March 24, 2009 5:44 AM
  • Hi justin,

    i'm facing the same issue. i'm using PRISM with MVVM. i attched a command for SelectedItemChanged event, but when the selected item's parent is collapsed, the parent becomes the newly selected item and the command gets executed for both the parent and for the last node down the tree

    for eg, if i have a treeview like this,

    Parent

      -Level1

        -Level1.1

     -Level2

        -Level2.1

    Now say, level 1.1 is selected and if i collapse on Level 1, event is fired for Level2(first) and then for Level 1. If collapse on Parent with tha same item selected, event is fired for Level2(first) and then for Parent.

    I think this is a bug.

    What i want is when i expand/collapse, don't change selected item and so prevent the event executing from multiple times.

    Sometimes the user just want to expand/collapse the tree to see the list if it is big. That is exactly our scenario and the customer doesn't want to change the selected item. We are building a large LOB application with over 100 screens and most of the views are injected based on treeview selection. That is where the app goes for a toss if i use this control..

    Waiting for your recommendation/suggestions....

    Thanks in advance,

    sam




    Tuesday, July 20, 2010 3:35 PM