Treeview i breaking my MVVM !!

11 posts, 2 answers
  1. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 21 Feb 2011 Link to this post

    Dear all,

    I have successfully implemented the RadTreeview with LoadOnDemand using QueryableDomainServiceCollectionView but in way that is breaking my MVVM pattern.

    I had follow the scenario described in this thread (very helpfull indeed):
    http://www.telerik.com/community/forums/silverlight/treeview/self-referencing-hierarchy-wcf-ria-services-level-display-problem.aspx

    WHY?

    I have to subscribe to the LoadOnDemand event and call the VM to load the data, then process the data back in the EventHandler where I need to assign the result entities to the itemsSource of the clicked item.

    How can this be achieved in the MVVM world....

    Best regards
    Waleed
  2. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 24 Feb 2011 Link to this post

    Hello Waleed Seada,

    You can use a Trigger to attach a command to the RadTreeView LoadOnDemand event:
    <telerik:RadTreeView x:Name="radTreeView"
                            IsLoadOnDemandEnabled="True"
                            ItemTemplate="{StaticResource ItemTemplate}"
                            ItemsSource="{Binding Items}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="LoadOnDemand">
                <i:InvokeCommandAction Command="{Binding ItemExpandedCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </telerik:RadTreeView>

    Where the ItemExpandedCommand should be defined in the RadTreeView DataContext:
    public class ViewModel
    {
        public ViewModel()
        {
            ItemExpandedCommand = new DelegateCommand((a) => { this.LoadOnDemandCommand(); }, (p) => { return true; });
     
                    ....
        }
        public DelegateCommand ItemExpandedCommand { get; set; }
     
        private void LoadOnDemandCommand()
        {
            //implement your LoadOndemand logic here
        }
     
        public ObservableCollection<DataItem> Items { get; set; }
    }

    I hope this info helps.

    Kind regards,
    Tina Stancheva
    the Telerik team
    Registration for Q1 2011 What’s New Webinar Week is now open. Mark your calendar for the week starting March 21st and book your seat for a walk through all the exciting stuff we ship with the new release!
  3. DevCraft banner
  4. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 25 Feb 2011 Link to this post

    I can see the solution comming through this... except I have some comlications.

    First the assembely System.Windows.Interactivity shows that the trigger should be defined as follows:
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="LoadOnDemand">
            <i:InvokeCommandAction CommandName="{Binding ExpandItemCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>

    I am using PRISM4 to define the commands in my VM as follows:

     

     

    public DelegateCommand<object> expandItemCommand;

     

     

     

    public ICommand ExpandItemCommand { get { return this.expandItemCommand; } }

     


    and finally in the constructor I have this eventhandler definition:

    this

     

     

    .expandItemCommand = new DelegateCommand<object>(ExpandItem);

    I tried this and got an exception when the page first loads:
    Set property 'System.Windows.Interactivity.InvokeCommandAction.CommandName' threw an exception.
    with the errorMessage saying:
    Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.String'.

     

    As you can see, I need to pass the clickeditem from the tree as a parameter to the eventhandler to do the real job (fetching the data).

    How can this be accomplished in the current scenario.

    Thank you very much
    Waleed
  5. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 26 Feb 2011 Link to this post

    Dear Tina,

    I have downloaded a recent version of the System.Windows.Interactivity.dll and it show the Command and it is also working perfectly.

    I just need to pass the current selected treeviewitem as a parameter through CommandParameter={Binding Path=GroupItems.CurrentItem}" but it isn't working ...

    How can this be accomplished in your opinion.

    Best regards
    Waleed

    EDIT:
    I also try to use the Binded ObservableServiceCollectionView GroupItems (that is binded to the treeview itemSource) but it is not changed with the selection happen to the treeviewitem.

    Regards
  6. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 02 Mar 2011 Link to this post

    Hi Waleed Seada,

    I attached a sample project that can help you get started. It implements LoadOnDemand functionality for the first level of a TreeView hierarchy. The RadTreeView SelectedItem is databound to a business property, which is also used to pass a CommandParameter to the LoadOnDemand() event handler.

    Kind regards,
    Tina Stancheva
    the Telerik team
    Registration for Q1 2011 What’s New Webinar Week is now open. Mark your calendar for the week starting March 21st and book your seat for a walk through all the exciting stuff we ship with the new release!
  7. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 04 Mar 2011 Link to this post

    Dear Tina,

    Appreciate your example ... I just can't get mine to work as yours. here is the details of my implementation.
    XAML declaration of the treeview with the
    <telerik:RadTreeView x:Name="TOA" Grid.Column="0" FontSize="11"
                                IsLineEnabled ="False"
                                ItemTemplate="{StaticResource ItemTemplate}" 
                                IsLoadOnDemandEnabled="True"
                                LoadOnDemand="TOAItemExpanded"
                                ItemClick="TOAItemExpanded"
                                SelectedItem="{Binding CurrentSelected}"
                                ItemsSource="{Binding GroupItems}">
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="LoadOnDemand">
                    <i:InvokeCommandAction Command="{Binding ExpandItemCommand}" 
                                                  CommandParameter="{Binding SelectedItem}"/>
                </i:EventTrigger>
            </i:Interaction.Triggers>
    </telerik:RadTreeView>

    And I have added the selecteditem property as follows:
    private group _currentSelected;
    public group CurrentSelected
    {
        get { return _currentSelected; }
        set { _currentSelected = value; RaisePropertyChanged("CurrentSelected"); }
    }

    Also the Delegate definition and eventhandler:
    public DelegateCommand<object> expandItemCommand;
      
    // In constructor
    this.expandItemCommand = new DelegateCommand<object>(ExpandItem);
      
    // The ICommand
    public ICommand ExpandItemCommand { get { return this.expandItemCommand; } }

    and finally the Eventhandler:
    private void ExpandItem(object treeviewitem)
    {
        if (treeviewitem == null) return;
        // get the clicked Item
        RadTreeViewItem clickedItem = treeviewitem as RadTreeViewItem;
        group dataItem = clickedItem.Item as group;
        // Get the children set of the selected node
        QueryableDomainServiceCollectionView<group> items = LoadGroupData(dataItem.group_id);
        items.LoadedData += (s, args) =>
        {
            clickedItem.ItemsSource = args.Entities;
            clickedItem.IsLoadOnDemandEnabled = args.Entities.Any();
        };
    }
    I always get treeviewitem == null true

    Please not that I attached an evenhandler to the groupitems currentchanged event as follows:

    GroupItems.CurrentChanged += GroupItem_Changed;


    to keep track and update the CurrentSelected attached in xaml to selecteditem of the treeview

    Thanks and best regards.
    Waleed
  8. Answer
    Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 09 Mar 2011 Link to this post

    Hello Waleed Seada,

    From the code snippets you sent I noticed that you are binding the CommandParameter to a SelectedItem property, but it seems that you don't have such data property in your model. I believe you mean to bind it to the CurrentSelected property instead.

    You need to keep in mind that in the InvokeCommandAction definition, you are binding the Command and CommandParameter properties to data properties from your view model, not to properties of the RadTreeView. Therefore when you bind the CommandParameter to the
    CurrentSelected property, the treeviewitem object that you will receive in the ExpandItem() event will be a data item, rather than a RadTreeViewItem.

    Also, I noticed the the RadTreeView SelectedItem property is bound in a OneWay mode (the default mode). However in order to update the
    CurrentSelected property whenever the RadTreeView SelectedItem is changed, you need to set the Binding Mode to TwoWay.

    I hope this info will help you.

    All the best,
    Tina Stancheva
    the Telerik team
    Registration for Q1 2011 What’s New Webinar Week is now open. Mark your calendar for the week starting March 21st and book your seat for a walk through all the exciting stuff we ship with the new release!
  9. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 12 Mar 2011 Link to this post

    Dear Tina,

    Your reply was very helpful to me, you made my day ... I successfully can get the currentitem when the treeview item is selected.
    I have more questions here:
    1- How can I do the same for the LoadOndemad event, I need to get the currentexpaned item as well.
    2- The radtreeview itemssource is bounded to a QDSCV, should this work as the radgridview, I mean when a row get selected in the radgrid the collection get notified about that?
    3- Is there any possibility to get the treeviewitem as commandparameter?

    I appreciate your reply indeed
    Waleed
  10. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 17 Mar 2011 Link to this post

    Hello Waleed Seada,

    When the RadTreeView ItemsSource is bounded to a QDSCV it should notify the collection for selected TreeViewItems when an appropriate binding exists.

    However, you cannot get the current expanded item since there isn't a RadTreeView property, which holds it. However, you can bind the IsExpanded property of the RadTreeViewItem to a property from your view model and use it to make sure whether the item is expanded or not. Also in a databinding scenario, you cannot get a RadTreeViewItem as CommandParameter, but you can create data properties to hold the information you need to access from each RadTreeViewItem.

    Regards,
    Tina Stancheva
    the Telerik team
  11. Answer
    Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 17 Mar 2011 Link to this post

    Hi Waleed Seada,

    Just to follow-up on this, I wanted to let you know that you can follow another approach for binding the LoadOnDemand command to a command from your ViewModel. You can take advantage of the MVVMLight framework and the EventToCommand behavior.

    You can examine the attached project for more info.

    Greetings,
    Tina Stancheva
    the Telerik team
  12. Waleed Seada
    Waleed Seada avatar
    241 posts
    Member since:
    May 2006

    Posted 19 Mar 2011 Link to this post

    Perfect,
    Exactly what I need ..

    Appreciate your help indeed.

    Best
    Waleed
Back to Top
DevCraft banner