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
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
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.
}
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
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