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

Hide Items in RadTreeView

7 Answers 212 Views
TreeView
This is a migrated thread and some comments may be shown as answers.
Raymond
Top achievements
Rank 1
Raymond asked on 05 Sep 2019, 03:36 AM

I am using the RadTreeView to display driver runs and the associated jobs but once a job is completed the driver can set an option to display or hide the completed jobs.  I am using a "DisplayJob" property to hide the job item if it has been completed (and the hide completed option has been set) as follows;

<DataTemplate x:Key="JobItemTemplate">
    <Grid
        IsVisible="{Binding Item.DisplayJob}"
        RowSpacing="0"
        Padding="0"
        Margin="0"
        BackgroundColor="{Binding Item.JobStatus, Converter={StaticResource StringToColourConverter}}">
 
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="1" />
        </Grid.RowDefinitions>
 
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="60" />
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="40" />
        </Grid.ColumnDefinitions>
 
        <Label
            Grid.Row="0"
            Grid.RowSpan="3"
            Grid.Column="0"
            Text="{Binding Item.SequenceNumber}"
            TextColor="{StaticResource SunburstOrange}"
            FontSize="36"
            HorizontalTextAlignment="Center"
            WidthRequest="60"
            HorizontalOptions="CenterAndExpand"
            VerticalOptions="CenterAndExpand" />
 
        ...
         
    </Grid>
</DataTemplate>

 

The problem is this does not remove the space the item was taking up in the visual tree.

I found this https://www.telerik.com/forums/radtreeviewitem-visibility in the forum butI'm not sure how to apply to my code.

7 Answers, 1 is accepted

Sort by
0
Raymond
Top achievements
Rank 1
answered on 05 Sep 2019, 03:39 AM

In case it helps, this is how the item templates are defined;

<telerikDataControls:RadTreeView
    x:Name="treeView"
    Grid.Row="1"
    Grid.Column="0"
    Grid.ColumnSpan="3" 
    ItemsSource="{Binding DriverRuns}">
     
    <telerikDataControls:TreeViewDescriptor
        TargetType="{x:Type viewModels:RunVm}"
        ItemsSourcePath="Jobs"
        ItemTemplate="{StaticResource RunHeaderTemplate}">
    </telerikDataControls:TreeViewDescriptor>
 
    <telerikDataControls:TreeViewDescriptor
        TargetType="{x:Type viewModels:JobVm}"
        ItemTemplate="{StaticResource JobItemTemplate}" />
</telerikDataControls:RadTreeView>
0
Lance | Manager Technical Support
Telerik team
answered on 05 Sep 2019, 03:26 PM

Hello Raymond,

That forum thread is for UI for WPF. In WPF you can change the ItemsPanel that the framework uses for a control that iterates over data items and renders them in containers.  However, this is not an option in Xamarin.Forms.

The approach you've taken does make sense and would work in frameworks that give you an option to collapse Visual Tree elements (e.g. WPF lets you set Visibility to Visible, Hidden or Collapsed).

The best approach for you would to have a separate collection for the TreeView's ItemsSource. then, only add the items in which the DisplayJob property is true.

For example:

// assume
Observablecollection<T> AllItems;
Observablecollection<T> TreeViewItems

// you would call this whenever you need the TreeView to be updated
private void UpdateTreeView()
{
    TreeViewItems.Clear();

    foreach(var item in AllItems)
    {
        if(item.DisplayJob)
        {
            TreeViewItems.Add(item);
        }
    }
}

Another option would be just to new-up the collection instead of Clearing and adding items. As long as you're calling OnPropertyChanged when the TreeViewItems property gets updated, you can just do this:

private void UpdateTreeView()
{
    var displayableItems = AllDrivers.Where(d => d.DisplayJob);

    TreeViewItems = new ObservableCollection<T>(displayableItems);
}

Note: If this jobs collection is a child of a top level object (i.e. Driver), then you would take the same approach, but the code would just need to iterate over the Jobs collection instead.

Regards,
Lance | Technical Support Engineer, Principal
Progress Telerik

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Raymond
Top achievements
Rank 1
answered on 12 Sep 2019, 03:06 AM

Hi Lance,

Thanks for that.  I tried your initial suggestion but this didn't work as you can't bind to a field - it has to be a property so I refactored my code as follows;

public ObservableCollection<JobVm> Jobs = new ObservableCollection<JobVm>();
 
public ObservableCollection<JobVm> DisplayedJobs
{
    get
    {
        List<JobVm> displayedJobs;
 
        if (_hideCompleted)
            displayedJobs = Jobs.Where(x => x.IsCompleted == false).OrderBy(x => x.Sequence).ToList();
        else
            displayedJobs = Jobs.OrderBy(x => x.Sequence).ToList();
 
        return new ObservableCollection<JobVm>(displayedJobs);
    }
}

 

When the user opts to hide the completed jobs it raises a PropertyChanged event for DisplayedJobs which should then update the display.  My problem now is;

  • When the application loads the list is displayed with all of the jobs.
  • When the user opts to hide the completed jobs theUI is updated however it now displays ever 2nd job (2, 4, 6, etc).
  • When the user changes the option to display all jobs the UI updates to display every 4th jobs.
  • Changing the option again to hide the completed jobs then displays every 8th job?

I updated the code to check what was being returned as follows;

public ObservableCollection<JobVm> Jobs = new ObservableCollection<JobVm>();
public ObservableCollection<JobVm> _displayedJobs = new ObservableCollection<JobVm>();
 
public ObservableCollection<JobVm> DisplayedJobs
{
    get
    {
        int sequence = 0;
        List<JobVm> displayedJobs;
 
        if (_hideCompleted)
            displayedJobs = Jobs.Where(x => x.IsCompleted == false).OrderBy(x => x.Sequence).ToList();
        else
            displayedJobs = Jobs.OrderBy(x => x.Sequence).ToList();
 
        _displayedJobs = new ObservableCollection<JobVm>(displayedJobs);
 
        if (_displayedJobs.Count() > 0)
        {
            sequence = _displayedJobs.Select(x => x.Sequence).First();
        }
 
        Trace.WriteLine($"{DateTime.Now.ToString("HH:mm:ss")}:= HideCompleted: {_hideCompleted} Displayed Jobs: {_displayedJobs.Count()} Sequence: {sequence}");
        return _displayedJobs;
    }
}

 

And the results were as follows;

[0:] 12:33:28:= HideCompleted: True Displayed Jobs: 19 Sequence: 1
[0:] 12:33:36:= HideCompleted: True Displayed Jobs: 19 Sequence: 1
[0:] 12:33:42:= HideCompleted: True Displayed Jobs: 19 Sequence: 1
[0:] 12:33:47:= HideCompleted: True Displayed Jobs: 19 Sequence: 1

This was as expected as none of the jobs were completed. I tried attaching a gif showing the results in the UI but it is slightly larger than the allowed 2Mb at 2.23Mb. Is there some other way I can get this file to you?

0
Raymond
Top achievements
Rank 1
answered on 12 Sep 2019, 03:09 AM

The results were;

[0:] 12:33:28:= HideCompleted: True Displayed Jobs: 19 Sequence: 1
[0:] 12:33:36:= HideCompleted: False Displayed Jobs: 19 Sequence: 1
[0:] 12:33:42:= HideCompleted: True Displayed Jobs: 19 Sequence: 1
[0:] 12:33:47:= HideCompleted: False Displayed Jobs: 19 Sequence: 1

Not those shown above.

0
Lance | Manager Technical Support
Telerik team
answered on 12 Sep 2019, 04:52 PM

Hi Raymond,

You can open a Support ticket which allows you to attach ZIP files, but you would need to sign in with the Telerik account that has the UI for Xamarin license (you appear to still be using a trial that has expired support). If your company purchased the license, you can have them assign you as the Licensed User in seconds via the Manage Licensed Users page.

Sharing Large Files

In the meantime, what you can do instead is to zip up the solution/projects and host it on a site like OneDrive/DropBox/etc. Then you can share a download link. Be sure to delete the bin and obj folders from each project before zipping it up, this will reduce the size to just a few MBs. For GIF captures, you can use a tool like SnagIt that will host the image/video on Screencast for you.

Keep in mind that these are public forums, while support tickets are private and protected by NDA.

Demo

I've taken a second look at the code for the TreeView and noticed that the top level binding is DriverRuns. not DisplayedJobs. I don't see where you've invoked PropertyChanged for the TreeView's ItemsSource. This would explain when the items aren't refreshing.

I've written a demo for you that does what you're looking for. All the code is in MainPage.xaml and MainPage.xaml.cs (including models and view model). Run it and check/uncheck the CheckBox to see completed items added/removed from the TreeView.

Below is a screenshot of the relevant parts of the code, in short it does the following in this order:

  1. CheckBox is toggled
  2. The True/False value of the checkbox determines what items are in the DisplayedJobs collection
  3. Refreshes the TreeView's ItemsSource so the TreeView is reloaded.

Regards,
Lance | Technical Support Engineer, Principal
Progress Telerik

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
0
Raymond
Top achievements
Rank 1
answered on 18 Sep 2019, 02:40 AM

Hi Lance,

Thanks for example code. I created a test app based on the information you provided which can be found at https://www.dropbox.com/sh/u943l5b71u0l2eu/AACHGAWHsAUJ_uT-xs550VWea?dl=0.  This works as anticipated however when I implemented the same changes in my production code I get the following error whenever the DriverRuns are updated for the 2nd time;

Java.Lang.IndexOutOfBoundsException
  Message=Inconsistency detected. Invalid item position 1(offset:-1).state:9 md5a5af569a83c1a3f5c3a8a63bd7d39860.RadExtendedListView{3c90dfa VFED..... ......ID 0,0-720,1162 #12}, adapter:com.telerik.widget.list.ListViewWrapperAdapter@a84d67b, layout:android.support.v7.widget.LinearLayoutManager@8394fab, context:md582ede9c73384f76ab3fc7788a7083452.MainActivity@c13ca6d

This error is raised when the line `PropertyUpdated(nameof(DriverRuns)); ` is executed (line 223 in RunSheet.xaml.cs) in the production code.

0
Lance | Manager Technical Support
Telerik team
answered on 18 Sep 2019, 01:16 PM

Hi Raymond,

That error means an item was being moved to a position that doesnt exist (IndexOut of Range / Out of Bounds). I don't call PropertyChanged manually on the DriverRuns object because it is being done at the right time by the setter.

Without being able to reproduce it, I can't test any possible fixes, so let me list some of the first things I'd try:

  1. Wait until the very last step to invoke any PropertyChange and ensure it is being invoked on the UI thread (Device.BeginInvoke)
  2. Reset the TreeView's ItemsSource by setting it to null first, then assign the newly updated list.

I suspect the only option is going to be #2 if you need to manually invoke PropertyChanged.

Regards,
Lance | Technical Support Engineer, Principal
Progress Telerik

Do you want to have your say when we set our development plans? Do you want to know when a feature you care about is added or when a bug fixed? Explore the Telerik Feedback Portal and vote to affect the priority of the items
Tags
TreeView
Asked by
Raymond
Top achievements
Rank 1
Answers by
Raymond
Top achievements
Rank 1
Lance | Manager Technical Support
Telerik team
Share this question
or