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

how to get to newly inserted row MVVM

2 Answers 226 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 21 Dec 2016, 11:54 AM

In response to a button command my VM inserts a record at index 0 into  the observablecollection that is bound to the gridview.

Now that I have it in the collection a new row automagically appears in the radgrid at the beginning. I'm trying to be a good boy and keep knowledge of my UI out of the VM. My gridview is marked as IsReadOnly = true. I only  allow editing via raddataform attached to the rowdetails. My questions are:

1. How to automatically expand the row details of a newly inserted row (using MVVM)?

2. Once they hit update the newly added row seems to be moved by the gridview to it's rightful place in the sort order. This is great.However, if you are using datapager the row could be moved to an unknown page leaving the user wondering where their new record went. I know there is a ScrollIntoView function, but I'm not sure I should be using that in a VM. Even if I did, how would I know what row to scroll to after it's been resorted? So, how can I get a newly added, newly sorted row to scroll to be the first row visible regardless of which page in the pager it lands and have it's rowdetail editor expanded using MVVM?

Any help would be greatly appreciated.

Thanks ... Ed

 

 

 

2 Answers, 1 is accepted

Sort by
0
Accepted
Stefan
Telerik team
answered on 22 Dec 2016, 12:28 PM
Hi Ed,

I will get straight to your questions.

1.   A possible approach for this would be to define a boolean IsExpanded property in your business object. When adding the new item to the source collection you should set it to True. Based on its value, the details of the row will be expanded or collapsed. This can be achieved through the DetailsVisibility property of GridViewRow and an IValueConverter. Please, take a look at the two snippets below.
<Style TargetType="{x:Type telerik:GridViewRow}">
    <Setter Property="DetailsVisibility"
            Value="{Binding IsExpanded, Converter={StaticResource conv}}" />
</Style>

public object Convert(object value, Type targetType,
    object parameter, System.Globalization.CultureInfo culture)
{
    var shouldExpand = (bool)value;
    if (shouldExpand)
    {
        return System.Windows.Visibility.Visible;
    }
 
    return System.Windows.Visibility.Collapsed;
}

2.   There is no out of the box mechanism for satisfying such requirement. For determining at which page the newly item is resorted you need to perform some manual calculations. You will need the index of the item from the Items collection of RadGridView. The data operations of the control are performed over this collection, thus when a sort operation is processed, the order of the elements in this collection will be as they appear in the UI. Having the index of the item and the overall item count, you can get the PageCount value of RadDataPager and set its PageIndex based on the performed calculation.

When having the needed page being set, you can scroll to the newly added item using the built-in scrolling mechanism of RadGridView. Though I cannot suggest a particular implementation, a possible solution for keeping the MVVM environment intact would be to utilize an Attached Behavior.

Hopefully, this helps. Feel free to update me should you need further assistance or have any concerns.

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 22 Dec 2016, 06:34 PM

Got it! Here's my solution and it works great.

The attached behavior is the right way to do this. Basically, when my "AddCommand" gets fired in my vm,

I add a new row to my ObservableCollection which is bound to the gridview.

I pick up the collection changed event in my behavior, find the new row, select it and expand it.

Tastes great! Less Filling!

I think I may finally be getting the hang of this MVVM thing.

Thanks for all the guidance ... Ed

 

<-- Add this to you namespaces -->
xmlns:support="clr-namespace:Yourapp.Support"
 
<-- add this just below the opening tag of the RadGridView
<i:Interaction.Behaviors>
    <support:AddNewDetailsItemBehavior/>
</i:Interaction.Behaviors>
 
// Next, create a class for your behavior, I made mine as generic as possible.
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Interactivity;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.GridView;
 
namespace YourApp.Support
{
    public class AddNewDetailsItemBehavior : Behavior<RadGridView>
    {
 
        #region Overrides
        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Unloaded += OnUnloaded;
            AssociatedObject.Items.CollectionChanged  += OnCollectionChanged;
        }
        #endregion
 
        #region Implementation
        private void OnUnloaded(object sender, System.Windows.RoutedEventArgs e)
        {
            AssociatedObject.Unloaded -= OnUnloaded;
            AssociatedObject.Items.CollectionChanged -= OnCollectionChanged;
        }
 
        private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (e.Action.ToString() != "Add") // I'm only interested in inserts.
                return;
            RadGridView gv = (RadGridView) AssociatedObject;
            var info = e.NewItems[0];
 
            RadDataPager Pager = gv.Parent.FindChildByType<RadDataPager>();
            int page = 0;
            // find the info we just inserted. Note that I always have an IsNew bool for my objects
             info = (from dynamic a in gv.Items
                  where a.IsNew == true
                  select a).FirstOrDefault();
            if (info == null)
            {
                // they  have some sorting going on and it's on another page
                // wade through and find it.
                for (int i = 1; i < Pager.PageCount; i++)
                {
                    Pager.PageIndex = i;
                    info = (from dynamic a in gv.Items
                          where a.IsNew == true
                          select a).FirstOrDefault();
                    page++;
 
                    if (info != null)
                        break;
 
                }
            }
            if (info == null)
                throw new Exception("Assertion failed in AddNewDetailsItemBehavior. Please contact support.");
 
            Pager.MoveToPage(page);
            gv.ScrollIntoViewAsync(info, (f) =>
            {
                int idx = gv.Items.IndexOf(info);
                gv.SelectedItem = gv.Items[idx];
                 
                gv.GetRowForItem(info).IsExpanded = true;
 
            });
       }
 
        #endregion
 
    }
}
Tags
GridView
Asked by
Randy Hompesch
Top achievements
Rank 1
Answers by
Stefan
Telerik team
Randy Hompesch
Top achievements
Rank 1
Share this question
or