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

toggling + and - on GridViewToggleRowDetailsColumn

4 Answers 528 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Randy Hompesch
Top achievements
Rank 1
Randy Hompesch asked on 09 Jan 2017, 02:10 PM

Hi,

I have all my code working great except for this one thing. When I add an item to the bound collection of the gridview my rowdetails template displays and all is well except that the + does not toggle to a -. How do I change this via code? I tried doing it in the OnCollectionChanged event (for the Add action) by setting the IsExpanded flag,  but when I try to do a GetRowForItem, it returns null. If I try to find the selected item via MyGrid.ChildrenOfType<GridViewRow>(), ALL the items are null.

Help!!!

Thanks ... Ed

4 Answers, 1 is accepted

Sort by
0
Lance | Senior Manager Technical Support
Telerik team
answered on 09 Jan 2017, 06:20 PM
Hi Randy,

I was not able to replicate the behavior you're seeing where the ToggleRowDetailsColumn's button doesn't change state. I have attached a small demo that accomplished what you're looking for.

Take the following steps to see it in action:

1 - Press button 1 to add a new Bookstore to the GridView
2 - Press button 2 to toggle any selected row's RowDetailsVisibility

Here's how it was accomplished.

First, get the selected row object by doing the following:

var selectedRow = BookstoreGridView.ItemContainerGenerator.ContainerFromItem(BookstoreGridView.SelectedItem) as GridViewRow;

Then, instead of IsExpanded, you can toggle the row's details visibility by using the DetailsVisibility property of the row.

selectedRow.DetailsVisibility = selectedRow.DetailsVisibility == Visibility.Collapsed
                ? Visibility.Visible
                : Visibility.Collapsed;


If you have any additional questions or you're still seeing a strange behavior, please update my attached demo so that it replicates the problem and reply back with it. We will take a look at it and investigate further.

Regards,
Lance | Tech Support Engineer, Sr.
Telerik by Progress
Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
0
Randy Hompesch
Top achievements
Rank 1
answered on 10 Jan 2017, 01:25 PM

Hi,

Let me give you some more info. In the attached behavior shown below starting on line 26 I have a series of commented questions. Using your suggestion, I tried :

gv.ChildrenOfType<GridViewRow>().First().DetailsVisibility    = Visibility.Visible

This works ... sort of. If the user sorts the grid by clicking on column header, and then clicks on my button to insert  a new row to the collection (MyDataContext.Insert(0, MyInfo) ), the new row shows up at the top where I want, however, for some reason a different row is expanded.

I've also attached a couple of screen shots.

Thanks for the help.

Ed

 

01.public class AddNewRowDetailsItemBehavior : Behavior<RadGridView>
02.{
03. 
04.    #region Overrides
05.    protected override void OnAttached()
06.    {
07.        base.OnAttached();
08.        AssociatedObject.Unloaded += OnUnloaded;
09.        AssociatedObject.Items.CollectionChanged += OnCollectionChanged;
10.    }
11.    #endregion
12. 
13.    private void OnUnloaded(object sender, System.Windows.RoutedEventArgs e)
14.    {
15.        AssociatedObject.Unloaded -= OnUnloaded;
16.        AssociatedObject.Items.CollectionChanged -= OnCollectionChanged;
17.    }
18. 
19.    private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
20.    {
21.        if (e.Action.ToString() == "Add")
22.        {
23. 
24.            RadGridView gv = (RadGridView) AssociatedObject;
25. 
26.            // if I try to clear the sort here the + does not change. If
27.            // I clear teh sort in teh click event of teh button in the view
28.            // it works. Why ???
29.            //gv.SortDescriptors.Clear();
30.            dynamic info = App.AppState.GetValue<dynamic>("NewInfo");
31. 
32.            if (info != null)
33.            {
34.                int idx = gv.Items.IndexOf(info);
35.                if (idx >= 0)
36.                {
37.                    gv.SelectedItem = gv.Items[idx];
38. 
39.                    // row is always null
40.                    //var row = gv.ItemContainerGenerator.ContainerFromItem(gv.SelectedItem) as GridViewRow;
41.                    //row.DetailsVisibility = Visibility.Visible;
42. 
43.                    //  this works!!! but only in an unsorted case. if I sort desc for some reason
44.                    //  another row is expanded even though I gv.SortDescriptors.Clear();
45.                    // The question is why is it failing in the sorted case?
46.                    // Also, gv.ChildrenOfType<GridViewRow>().First() returns null in teh debugger's immediate
47.                    // window.
48.                    gv.ChildrenOfType<GridViewRow>().First().DetailsVisibility = Visibility.Visible;
49. 
50. 
51.                    // x.Item is always null, why??
52.                    //foreach (var x in gv.ChildrenOfType<GridViewRow>())
53.                    //{
54. 
55.                    //}
56. 
57.                    // r ends up null. Why??
58.                    //var r = (GridViewRow) gv.ItemContainerGenerator.ContainerFromItem(gv.SelectedItem);
59.                    //r.DetailsVisibility = Visibility.Visible;
60. 
61.                }
62. 
63.                App.AppState.Remove("NewInfo");
64.            }
65.        }
66.        else if (e.Action.ToString() == "Reset")
67.        {
68.            RadGridView gv = (RadGridView) AssociatedObject;
69.            dynamic info = App.AppState.GetValue<dynamic>("NewInfo");
70.            if (info != null)
71.            {
72.                dynamic item = (from dynamic a in gv.Items where a.PK == info.PK select a).First();
73.                gv.ScrollIntoView(item);
74.                App.AppState.Remove("NewInfo");
75.            }
76. 
77.        }
78. 
79.    }
80.}
0
Stefan
Telerik team
answered on 13 Jan 2017, 11:18 AM
Hi Ed,

Thanks for the details provided.

Firstly, I would like to shed some light on the recommended usage of the RowDetails mechanism and the RadGridView component as a whole. The control provides a virtualized environment for its items, meaning that the cell containers are reused when the user scrolls horizontally or vertically. Thus, it is highly not recommended to traverse the visual tree and directly access and modify the visual elements(rows, cells) of the control. Such approach can lead to unpredictable results. Since RadGridView is a data-bound component, these operations must be implemented on data level instead.

So, there are two possible solutions that can be implemented. The first one would be to use the Hierarchy mechanism that RadGridView provides. The control has a ExpandHierarchyItem method to which you can pass the item that needs to be expanded. With such approach, the GridViewToggleButton that expands and collapses the hierarchy will be updated out of the box.

If aforementioned approach is not feasible for you, you can stick to the RowDetails mechanism, but you will need to write some additional logic. A possible solution would be to utilize the RowLoaded event of the control. Since it is raised for each row being loaded in the viewport, you need to ensure that the RowDetails are expanded only for the item that is newly added. This can be achieved using the logic demonstrated in the following steps.

1.   Define a boolean shouldExpand flag.

2.   When the data item is being added, set this flag to true.
private void AddStore_OnClick(object sender, RoutedEventArgs e)
{
    var vm = DataContext as MainViewModel;
     
    // Add a bookstore
    vm?.Bookstores.Add(new Bookstore() { Title = "Added Book" });
 
    shouldExpand = true;
    // select it in the
    BookstoreGridView.SelectedItem = vm?.Bookstores.LastOrDefault();
}

3.   As this raises the RowLoaded event, check the boolean flag and ensure that the row is loaded only for the last item in the source collection.
private void BookstoreGridView_RowLoaded(object sender, RowLoadedEventArgs e)
{
    var item = e.DataElement;
    var items = this.BookstoreGridView.Items;
 
    if (shouldExpand && items.IndexOf(item) == items.Count - 1)
    {
        (e.Row as GridViewRow).DetailsVisibility = Visibility.Visible;
        shouldExpand = false;
    }
}

I hope you find one of these suggestions useful in implementing the desired behavior. Feel free to update me should you need further assistance or have any concerns.

Best Regards,
Stefan X1
Telerik by Progress
Want to extend the target reach of your WPF applications, leveraging iOS, Android, and UWP? Try UI for Xamarin, a suite of polished and feature-rich components for the Xamarin framework, which allow you to write beautiful native mobile apps using a single shared C# codebase.
0
Randy Hompesch
Top achievements
Rank 1
answered on 16 Jan 2017, 01:11 PM

Oh boy, I've got some studying to do. I'll read up and see if I can straighten this out.

Thanks for setting me on the correct path.

Ed

Tags
GridView
Asked by
Randy Hompesch
Top achievements
Rank 1
Answers by
Lance | Senior Manager Technical Support
Telerik team
Randy Hompesch
Top achievements
Rank 1
Stefan
Telerik team
Share this question
or