This is a migrated thread and some comments may be shown as answers.

BringIntoView for MVVM?

4 Answers 546 Views
TreeView
This is a migrated thread and some comments may be shown as answers.
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
Bob asked on 20 Dec 2011, 07:03 PM
Hello,

I have a RadTreeView using a templated ItemsSource bound to a node collection in the view model.  I have implemented a search on the tree, and the found node is programmatically selected within the view model (there is no code in the view).  Do you have an example of how to bring the selected node into view using this type of MVVM structure?

Thanks for any help.

4 Answers, 1 is accepted

Sort by
0
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
answered on 20 Dec 2011, 09:17 PM
I believe I have found the answer.  Using Josh Smith's behavior as a starting point (http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx), I modified to reference RadTreeViewItem and called BringItemIntoView.  This seems to work so far.

Edit:  Still having a problem with collapsed items.  I try calling expand on all nodes in the path before selecting and bringing into view, but the item is not within view when all is done.
0
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
answered on 22 Dec 2011, 04:16 PM
Does anyone have a suggestion for how to ensure that a collapsed item is fully expanded before BringItemIntoView is called?

When the tree is first loaded and not expanded, BringItemIntoView does not work on an item that is within a collapsed node (I assume this is an item that is not "immediate").  However, if the item is expanded into view at least once, then BringItemIntoView will work after that.  I am trying to figure out a way to first expand the path before programmatically selecting the item into view, but no matter what I try, the item does not scroll into view.  Is this because the expanding is done on some type of delay?
0
Accepted
Hristo
Telerik team
answered on 23 Dec 2011, 09:29 AM
Hello Bob,

TreeView creates its visual items (TreeViewItem containers) as lazy as possible. Thus when item has not been expanded its children will not be created. Calling bring into view for container that is not yet created will have no effect.
As you have noticed, expanding item will force its children to be created (in case the virtualization is switched off). However, expanding item programmatically is asynchronous operation, i.e. function call returns but containers are generated at some later point in time.
I would suggest you take a look at this blogpost http://blogs.telerik.com/xamlteam/posts/11-01-12/treeview-bringintoview.aspx . It should work for and fit in your case.

Greetings,
Hristo
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

0
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
answered on 23 Dec 2011, 07:08 PM
Thank you Hristo, this helped me solve the problem. 

Just so everyone is aware, the method presented by Josh Smith in my post above will not work with the RadTreeView.  This is because the items of the tree that are initially collapsed are not actually instantiated, so therefore the selected event will never be registered.  To work around this, I used a GalaSoft MVVM messenger event instead, and handled the message in a behavior that brings the item into view.  Here is the general code I used.

First, I created a behavior in the View namespace:
public class TreeSelectionBehavior : Behavior<FrameworkElement>
{
    Messenger messenger = Messenger.Default;
 
    protected override void OnAttached()
    {
        base.OnAttached();
 
        messenger.Register<GalaSoft.MvvmLight.Messaging.DialogMessage>(this, Identifier, ItemSelected);
    }
 
    public string Identifier { get; set; }
 
    public MyTreeGenericNode SelectedNode
    {
        get { return (MyTreeGenericNode)GetValue(SelectedNodeProperty); }
        set { SetValue(SelectedNodeProperty, value); }
    }
 
    // Using a DependencyProperty as the backing store for the selected node object.
    public static readonly DependencyProperty SelectedNodeProperty =
        DependencyProperty.Register("SelectedNode", typeof(MyTreeGenericNode), typeof(TreeSelectionBehavior), new UIPropertyMetadata(null));
 
    public RadTreeView TreeView
    {
        get { return (RadTreeView)GetValue(TreeViewProperty); }
        set { SetValue(TreeViewProperty, value); }
    }
 
    // Using a DependencyProperty as the backing store for the RadTreeView.
    public static readonly DependencyProperty TreeViewProperty =
        DependencyProperty.Register("TreeView", typeof(RadTreeView), typeof(TreeSelectionBehavior), new UIPropertyMetadata(null));
 
    public void ItemSelected(GalaSoft.MvvmLight.Messaging.DialogMessage dm)
    {
        Assert.IsNotNull(SelectedNode);
        Assert.IsNotNull(TreeView);
 
        TreeView.BringPathIntoView(SelectedNode.DisplayPath);
    }
}

The behavior is added to the XAML and bound to the selected item and tree.  The reference to i: is for the System.Windows.Interactivity namespace.  The reference to v: is for the View namespace:

<i:Interaction.Behaviors>
    <v:TreeSelectionBehavior x:Name="MyTreeSelectionBehavior" Identifier="TreeSelectionBehavior"
                         TreeView="{Binding ElementName=MyRadTreeView}" SelectedNode="{Binding CurrentSelectedItem}" />
</i:Interaction.Behaviors>

Now, in the view model, I message the behavior when the selection is updated:

CurrentSelectedItem = NodeFoundFromSearch;
 
GalaSoft.MvvmLight.Messaging.Messenger mes = GalaSoft.MvvmLight.Messaging.Messenger.Default;
mes.Send(new GalaSoft.MvvmLight.Messaging.DialogMessage("Tree Selection Behavior", res =>
{
}),
    "TreeSelectionBehavior");

Make sure to unregister the message in the cleanup of the view:
messenger.Unregister<GalaSoft.MvvmLight.Messaging.DialogMessage>(MyTreeSelectionBehavior);

One final note - the node class that is used as items source must have a ToString() override that represents the name of the path element for the node:
public override string ToString()
{
    return this.Name;
}

Tags
TreeView
Asked by
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
Answers by
Bob
Top achievements
Rank 3
Iron
Iron
Veteran
Hristo
Telerik team
Share this question
or