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

Treeview i breaking my MVVM !!

10 Answers 280 Views
TreeView
This is a migrated thread and some comments may be shown as answers.
Waleed Seada
Top achievements
Rank 2
Waleed Seada asked on 22 Feb 2011, 01:13 AM
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

10 Answers, 1 is accepted

Sort by
0
Tina Stancheva
Telerik team
answered on 24 Feb 2011, 05:33 PM
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!
0
Waleed Seada
Top achievements
Rank 2
answered on 25 Feb 2011, 02:48 PM
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
0
Waleed Seada
Top achievements
Rank 2
answered on 26 Feb 2011, 06:10 PM
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
0
Tina Stancheva
Telerik team
answered on 02 Mar 2011, 02:24 PM
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!
0
Waleed Seada
Top achievements
Rank 2
answered on 04 Mar 2011, 02:13 PM
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
0
Accepted
Tina Stancheva
Telerik team
answered on 09 Mar 2011, 04:09 PM
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!
0
Waleed Seada
Top achievements
Rank 2
answered on 12 Mar 2011, 04:39 PM
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
0
Tina Stancheva
Telerik team
answered on 17 Mar 2011, 10:57 AM
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
0
Accepted
Tina Stancheva
Telerik team
answered on 17 Mar 2011, 02:20 PM
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
0
Waleed Seada
Top achievements
Rank 2
answered on 20 Mar 2011, 01:38 AM
Perfect,
Exactly what I need ..

Appreciate your help indeed.

Best
Waleed
Tags
TreeView
Asked by
Waleed Seada
Top achievements
Rank 2
Answers by
Tina Stancheva
Telerik team
Waleed Seada
Top achievements
Rank 2
Share this question
or