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

Virtual mode + custom cell DataTemplate = problems

18 Answers 779 Views
GridView
This is a migrated thread and some comments may be shown as answers.
Eugen Rata
Top achievements
Rank 1
Eugen Rata asked on 03 Jan 2010, 12:20 AM
I have such a code for the grid I'm using
        <telerik:GridViewDataColumn Header="Type" DataMemberBinding="{Binding TypeCombo}"
          <telerik:GridViewDataColumn.CellTemplate> 
            <DataTemplate> 
              <telerikInput:RadComboBox ItemsSource="{Binding TypeCombo.ItemsSource}"  
                SelectedIndex="{Binding TypeCombo.SelectedIndex, Mode=TwoWay}"  
                IsEnabled="{Binding IsComboTypeEnabled}"/> 
            </DataTemplate> 
          </telerik:GridViewDataColumn.CellTemplate> 
        </telerik:GridViewDataColumn> 
 

when EnableRowVirtualization is set to true (which is by default) that creates a lots of issues.
When scrolling the grid, up & down, cause ComboBoxes are reused, they get filled with wrong values and because of that when TypeCombo.SelectedIndex get's called I get a lot of "Index out of bounds" exception. If I set EnableRowVirtualization=false, everything works as expected. 
There are 15 such columns with custom CellTemplate and DataTemplate.

Something must be done here, or at least make by default that EnableRowVirtualization is false, unless you expect that most of people don't use Lookup comboboxes in their grids, that is very false for most of LOB applications.
And by the way, I do have like 40 rows, and when EnableRowVirtualization=true, the scrolling is much slower than virtual mode is set to false.

P.S. I'm using latest internal build available as of 1/2/2010.

18 Answers, 1 is accepted

Sort by
0
Milan
Telerik team
answered on 07 Jan 2010, 09:50 AM
Hello Eugen Rata,

This is a strange problem. Although the grid reuses some of its elements the DataContext for each item is kept in sync and you should not get incorrect values. Could you please send us your project so that we can observe the issue and try to provide a solution.


Regards,
Milan
the Telerik team

Instantly find answers to your questions on the new Telerik Support Portal.
Watch a video on how to optimize your support resource searches and check out more tips on the blogs.
0
Pedro
Top achievements
Rank 1
answered on 07 Mar 2011, 12:17 PM
Hello,

Do you have a solution ? I have the same issue...
Thanks in advance.

Best regards,
Pedro
0
Vlad
Telerik team
answered on 07 Mar 2011, 12:47 PM
Hi,

 
Since this thread was more than a year ago can you post more info about the problem at your end the the grid version? 

Kind regards,
Vlad
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
Rupendra
Top achievements
Rank 1
answered on 19 Apr 2011, 08:38 PM
I am having the same issue as the one above. The scenario is described below:

The grid ItemSource property is getting bound to a structure which is something like given below
public const string RowDataPropertyName = "RowData";
private ObservableCollection<DetailsGridRowModel> m_RowData;
public ObservableCollection<DetailsGridRowModel> RowData
{
    get
    {
        return m_RowData;
    }
    set
    {
        if (m_RowData == value)
        {
            return;
        }
          
        m_RowData = value;
        OnNotifyPropertyChanged(RowDataPropertyName);
    }
}

Here each column has a CellTemplate which contains a custom control.

     .
     .
     .

int i = 0;
foreach (var col in ColumnsCollection)
{
    GridViewDataColumn column = new GridViewDataColumn();
    column.CellTemplate = GetDataboundTemplate(i);
      
    // do something with col here
      
    GridView.Columns.Add(column);
    i++;
}
     .
     .
     .
  
     public DataTemplate GetDataboundTemplate(int columnIndex)
        {
            StringBuilder xaml = new StringBuilder();
            xaml.Append("<DataTemplate xmlns=\" [namespace] \" xmlns:my=\" [namespace] \">");
            xaml.Append("<my:DetailsGridItemView Context=\"{Binding ColumnData[" + columnIndex + "]}\" />");
            xaml.Append("</DataTemplate>");
            DataTemplate template = XamlReader.Load(xaml.ToString()) as DataTemplate;
            return template;
        }


The DetailsGridItemView control uses the Context property to render itself correctly.

The correct behavior for the grid is to bind each row to an instance of DetailsGridRowModel. When I disable the row and column virtualization everything works fine.

However, when I don't have them set explicitly or I enable them explicitly the followng behavior starts happening.
  • The grid starts to re-bind data to a control that is no-longer visible and hence might be re-used.
  • The data that gets picked up for binding is not in the correct order. So the order of items gets lost on sort and that causes a lot of problems and confusion.

Let me illustrate. Say  the number of rows visible is 5 and the data for each row is the following list. Lets also assume that the == bars represent the top and bottom edges of the grid control.

let's say my list is containing the following data
  • a
  • b
  • c
  • d
  • e
  • f
  • g
  • h
  • i
  • j

This is what the user sees then the grid first renders.

==================

  • a
  • b
  • c
  • d
  • e

==================

  • ? <can't see this right now>
  • ? <can't see this right now>
  • ? <can't see this right now>
  • ? <can't see this right now>
  • ? <can't see this right now>

 

Now lets assume that the user scolls to the bottom. The user sees the following.

  • ? <can't see this right now>  
  • ? <can't see this right now> 
  • ? <can't see this right now> 
  • ? <can't see this right now> 
  • ? <can't see this right now> 

===================

  • f
  • g
  • h
  • i
  • j
===================

However now when the user scrolls up, the grid does not pick up the items in the list in the correct order. So this is what the user might see (I say might since what gets picked up and bound doesn't seem to be deterministic.)

==================

  • g
  • i
  • a
  • b
  • d

==================

  • ? <can't see this right now>
  • ? <can't see this right now>  
  • ? <can't see this right now>  
  • ? <can't see this right now>  
  • ? <can't see this right now>  

If you notice in the illustration above, I have tried to show that the list shown to the user is not fixed at all. It actually changes and depends on various things which change the timing of the the events firing inside such as
  • The user stop scrolling and removed the mouse from the scrollbar when he reached at the bottom (as in mousebuttonup event fired or not) and then scrolled up again.
  • OR The user scrolled to the bottom and with mouse button still down scrolled to the top slowly or very quickly, etc.

 
In fact sometimes if the user now scrolls down this is what he might see which absolutly confuses the user.

  • ? <can't see this right now>
  • ? <can't see this right now>
  • ? <can't see this right now>

==================

  • b
  • d
  • c  
  • f

==================  

  • ? <can't see this right now>  
  • ? <can't see this right now>  


In the real solution I have about 60 rows and 30 are visible on the grid at any time.

0
Rupendra
Top achievements
Rank 1
answered on 25 Apr 2011, 07:21 PM
This issue was taken care by the following procedure.
Binding to the properties was done only in XAML (xaml binding and using converters). Code did not relied on binding the properties to different parts of the control.
0
Ed
Top achievements
Rank 1
answered on 07 Jul 2011, 12:49 AM

Hi,

I'm currently using version 2010.3.1314.1040. Our gridview typically contains over 1000 rows. One column uses a data template that has a user control, which data binds to a view model.

With virtualization enabled, we see the behavior described in this thead. The cell value bound changes as you vertically scroll the cell into and out of view. As a former poster describes, the value picked up for binding seems to be re-used or in the wrong order.

 

I've also tried on the 2011.1.419 relase, but see the same behavior.

Please advise. 



0
Vlad
Telerik team
answered on 07 Jul 2011, 06:42 AM
Hi,

 Can you post an example where we can reproduce this with our latest official version - Q1 2011 SP1?

All the best,
Vlad
the Telerik team

Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

0
Calvin
Top achievements
Rank 1
answered on 15 Jul 2011, 08:28 PM
At your request we have prepared a test application which illustrates the problem which we are experiencing.   

Here is a link to our project files:  http://techsupportfromcal.com/VirtualizationScrollingProblem/VirtualizationScrollingProblem.zip

This is a matter of considerable urgency for us.  Thanks for your assistance. 

Quoting from the ReadMe file in our test application:
 
         * This test application illustrates a problem which we are experiencing with our Telerik Silverlight GridView. 
         * The GridView has three columns which display images. The first image column contains a standard Silverlight
         * Image Control.  The second column contains a Silverlight User Control which in turn contains a Silverlight 
         * Image Control.  The third column shows a Silverlight Image Control hosted in a Silverlight Custom Control.
         * 
         * As can be seen from running this application, the first two columns display the correct images when
         * scrolling but the third column does not.  As you scroll, the images in the third column come from
         * other rows as the Telerik virtualization process reuses some grid components to improve performance.
         * If you set the  EnableRowVirtualization property to False, this problem goes away. However, our data
         * sets are often very large and setting this property to False results in an unacceptable degradation
         * in performance.  
         * 
         * The third image column also contains a textblock which displays the Identifier Name.  As can be
         * seen, this value is correct even though the wrong image is usually displayed. 
         * 
         * We have tried both the User Control and Custom Control approaches in our application and both
         * exhibit this scrolling problem.  Of course, our actual controls are much more complex than this 
         * sample application. 
         * 
         * This problem did not occur with the initial release of the Telerik controls from 2010 Q3. 
         * We first noticed this problem after applying SP1 to the Q3 release.  This test application
         * as requested by Telerik support uses the Q1 2011 release.  



    
0
Calvin
Top achievements
Rank 1
answered on 22 Jul 2011, 12:59 AM
Could you please advise us regarding any progress in examining this issue.    We are actively working on finding a satisfactory work around but so far we have not developed an acceptable solution.  

Thanks.  
0
Vlad
Telerik team
answered on 22 Jul 2011, 08:13 AM
Hi,

 We've checked your scenario with the standard Microsoft Silverlight DataGrid and the behavior is exactly the same. It seems that the problem is in your BasicStructure component - please verify this!

Best wishes,
Vlad
the Telerik team

Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

0
Calvin
Top achievements
Rank 1
answered on 23 Jul 2011, 02:21 AM
Thanks for the update.

1. Our application uses the Telerik Grid Control, not the Microsoft Grid Control and at least as of this point we are not looking to switch.

2. I would be happy to review any suggestions which you have regarding a possible problem with the BasicStructure component in my test application.  However, for purpose of creating this test application I made this component as simple as possible (our actual application is much more complicated).  It consists of nothing more than a custom control with two dependency properties and a UI consisting of a textblock and an image control.  The textblock refreshes correctly but the image control does not.  I don't mind at all removing the textblock since we don't actually have one of those in our real application but I can't remove the image control because that is the whole point of this column in our application.  

3.  This test application works just fine with your Q3 2010 controls (pre SP1).  Here's a link:
  http://techsupportfromcal.com/VirtualizationScrollingProblem/VirtualizationScrollingProblemQ32010.zip
If this test application works just fine with an earlier version of your controls but is broken with the current version of your controls, I would conclude that you must have changed something in how your controls work.  That is what we would like you to check into.  

4.  In our actual application we have two columns which are causing this problem -- one with an image and the other with a list box.  It didn't seem necessary to illustrate both problems since a fix for one of them will most likely provide a solution for both of them.  We have tested many different variations of these controls in our application (both Silverlight UserControls and Silverlight Custom Controls) and they all have this same problem. 
0
Vlad
Telerik team
answered on 25 Jul 2011, 07:37 AM
Hello,

 Here is how to change your custom control + converter to fix this:

<Style TargetType="CustomControls:BasicStructure">
        <Setter Property="Background" Value="White" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="CustomControls:BasicStructure">
                    <Grid x:Name="LayoutRoot" Background="{TemplateBinding Background}">
                            <StackPanel Orientation="Vertical">
                                <TextBlock x:Name="txbImageName"                                   
                                    Text="{Binding RelativeSource={RelativeSource TemplatedParent},  Path=ImageName}"    />
                                <Image x:Name="StructureImage"
                                       Source="{Binding RelativeSource={RelativeSource TemplatedParent},
                                                    Path=ImageName, Converter={StaticResource imageNameToImageConverter}}"                                      
                                        Height="100" Width="100"  />                               
                            </StackPanel>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

public class BasicStructureToImageConverter  :IValueConverter
    {
 
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string imageName = value as string;
            Uri uri = new Uri(@"http://localhost:6449" + "/images/"
                       + HttpUtility.UrlEncode(imageName) + ".png", UriKind.Absolute);
            return new BitmapImage(uri);
        }
 
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

All the best,
Vlad
the Telerik team

Register for the Q2 2011 What's New Webinar Week. Mark your calendar for the week starting July 18th and book your seat for a walk through of all the exciting stuff we will ship with the new release!

0
Calvin
Top achievements
Rank 1
answered on 26 Jul 2011, 10:20 PM
Thanks for your response.  

I guess that one of the disadvantages of simplifying our test application to remove most of the complexities of our real application is that some of the constraints of our application are no longer clear.  Your proposed solution would work nicely in our case if we needed only a simple string in our value converter.  In our actual application, however, we need four items of data inside the value converter:

    1.   a string which via some business logic is converted into the name of the file for our image,

    2.   a specification of which default image to use if there is no image corresponding to that file name,

    3.   the height and

    4.   the width of the desired image.

That is the reason why our real application and the test application built to simulate the real application, pass in an object which can include each of those four values as properties.
0
Calvin
Top achievements
Rank 1
answered on 11 Aug 2011, 03:02 AM
In the absence of a fix for this problem could we just get a confirmation that if we need to pass an object to our value converter, for versions of your RadGridView later than 2010 Q3, there is no simple solution to this virtualization-scrolling problem. 

Thanks.
0
Mikle
Top achievements
Rank 1
answered on 26 Aug 2011, 09:30 AM
I have a little example of this problem.
Sample application generates some data with selected checkbox in first column.
Run application. Deselect checkbox in first row. Than scroll down using keyboard. Note selection bar in some rows and wrongly deselected checkboxes.

XAML:
<UserControl x:Class="GridViewCellTemplateBug.MainPage"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
  
    <Grid x:Name="LayoutRoot" Background="White">
        <telerik:RadGridView x:Name="rgvProducts" Grid.Row="1" Margin="0,10,0,5" CanUserFreezeColumns="False" GridLinesVisibility="Both"
                        HorizontalAlignment="Stretch" VerticalAlignment="Stretch" FontSize="10" FontWeight="Normal" Height="Auto" ShowGroupPanel="False" 
                        IsFilteringAllowed="True"
                        AutoGenerateColumns="False" IsReadOnly="False" CanUserSelect="False">
            <telerik:RadGridView.Columns>
                <telerik:GridViewDataColumn Header="Select" >
                    <telerik:GridViewDataColumn.CellTemplate>
                        <DataTemplate>
                            <CheckBox IsChecked="{Binding Selected}" IsEnabled="True" HorizontalAlignment="Center" />
                        </DataTemplate>
                    </telerik:GridViewDataColumn.CellTemplate>
                </telerik:GridViewDataColumn>
                <telerik:GridViewDataColumn Header="Description" UniqueName="SKUDescription" IsReadOnly="True" />
            </telerik:RadGridView.Columns>
        </telerik:RadGridView>
    </Grid>
</UserControl>

Code:
using System.Collections.Generic;
using System.Windows.Controls;
using System.ComponentModel;
  
namespace GridViewCellTemplateBug
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            ProductCollection itemList = new ProductCollection();
            for (int i = 0; i < 100; i++)
            {
                Product item = new Product();
                item.Selected = true;
                item.SKUDescription = "Description" + i.ToString() + "   number" + i.ToString() + i.ToString();
                itemList.Add(item);
            }
            rgvProducts.ItemsSource = itemList;
        }
    }
  
    public class Product : object, INotifyPropertyChanged
    {
        private bool _Selected;
        public string SKUDescription { get; set; }
        public bool Selected
        {
            get { return _Selected; }
            set
            {
                _Selected = value;
                NotifyPropertyChanged("Selected");
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
    public class ProductCollection : List<Product>
    {
        public ProductCollection() : base() { }
        public ProductCollection(Product[] items)
            : base()
        {
            if (items != null)
            {
                foreach (Product item in items)
                {
                    this.Add(item);
                }
            }
        }
    };
}

0
Autolog
Top achievements
Rank 1
answered on 03 Jun 2014, 01:22 PM
I ran into the same issue with a radiobutton, and short of extending GridViewColumn into my own GridViewRadioButtonColumn, I solved it by creating a behavior which refreshes the binding on the radio buttons manually when the layout updates. It could easily be changed into a behavior for a checkbox:

public class VirtualizedRadioButtonBehavior : Behavior<RadioButton>
{
    protected override void OnAttached()
    {
        AssociatedObject.LayoutUpdated += AssociatedObject_LayoutUpdated;
        base.OnAttached();
    }
 
    protected override void OnDetaching()
    {
        AssociatedObject.LayoutUpdated -= AssociatedObject_LayoutUpdated;
        base.OnDetaching();
    }
 
    void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
    {
        BindingExpression binding = AssociatedObject.GetBindingExpression(RadioButton.IsCheckedProperty);
        if (null != binding)
        {
            binding.UpdateSource();
        }
    }
}

XAML:

<RadioButton IsChecked="{Binding Value}"  Command="{Binding ChangeValueCommand}">                           <i:Interaction.Behaviors>
        <behaviors:VirtualizedRadioButtonBehavior/>
    </i:Interaction.Behaviors>
</RadioButton>



I also tried a version where, instead of evaluating the binding, I had a property to compare the bound value to the actual IsChecked value:

public class VirtualizedRadioButtonBehavior : Behavior<RadioButton>
    {
        public DependencyProperty SynchronizedPropertyProperty = DependencyProperty.Register("SynchronizedProperty", typeof(bool?), typeof(VirtualizedRadioButtonBehavior), new PropertyMetadata(null));
 
        public bool? SynchronizedProperty
        {
            get { return (bool?)GetValue(SynchronizedPropertyProperty); }
            set { SetValue(SynchronizedPropertyProperty, value); }
        }
 
        protected override void OnAttached()
        {
            AssociatedObject.LayoutUpdated += AssociatedObject_LayoutUpdated;
            base.OnAttached();
        }
 
        protected override void OnDetaching()
        {
            AssociatedObject.LayoutUpdated -= AssociatedObject_LayoutUpdated;
            base.OnDetaching();
        }
 
        void AssociatedObject_LayoutUpdated(object sender, EventArgs e)
        {
            if (SynchronizedProperty != AssociatedObject.IsChecked)
            {
                AssociatedObject.IsChecked = SynchronizedProperty;
            }
        }
    }


I am not sure if it's any faster, but I settled for refreshing the binding, because the usage was simpler.
0
Tim
Top achievements
Rank 1
answered on 18 Jul 2015, 12:41 AM

Hi Telerik,

 A customer of ours is having this issue with the grid.  When the grid first displays all is well.  When they scroll down and then scroll back up to the top, the text in one of the columns changes to different values.  Unfortunately it is something that we have been unable to replicate in house.

 Reviewing our xaml, we note that the GridViewDataColumn columns that are teh problematic are ones where we have a custom CellTemplate defined.  

Researching your forum I came across this link: http://www.telerik.com/forums/difference-between-cellstyle-template-and-celltemplate

I have now reworked the xaml to use CellStyle instead of CellTemplate.

In house everything works as is and I am hopeful to supply this change to our customer to have them try it.

In trying to understand if this will help and if so why I used JustDecompile on the Telerik.Windows.Control.GridView.dll and note that in Telerik.Windows.Control.GridView.DataCellsPresenter.SyncProperties() method there is a NotifyPropertyChanged call for CellStyle only.  there is no call for CellTemplate.

Should Telerik also have a NotifyPropertyChanged call to CellTemplate in ​this SyncProperties() method and until it is added should we use CellStyle in our Xaml to assure everything stays synced when Row Virtualization is used?

 - Tim

 

 â€‹

 

0
Dimitrina
Telerik team
answered on 21 Jul 2015, 02:17 PM
Hi,

Would you please share how have you defined the hyperlink columns? Generally such issues may be observed when working with the visual elements (i.e. GridViewCell). You can also refer to the documentation on Styling or content mixed-up on scrolling.

A way to diagnose if this is the reason would be to disable RadGridView's UI virtualization. Please take a look at this article for a reference on UI Virtualization

How does Hyperlink Column or Dynamic Hyperlink Column work for you?

Regards,
Dimitrina
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
GridView
Asked by
Eugen Rata
Top achievements
Rank 1
Answers by
Milan
Telerik team
Pedro
Top achievements
Rank 1
Vlad
Telerik team
Rupendra
Top achievements
Rank 1
Ed
Top achievements
Rank 1
Calvin
Top achievements
Rank 1
Mikle
Top achievements
Rank 1
Autolog
Top achievements
Rank 1
Tim
Top achievements
Rank 1
Dimitrina
Telerik team
Share this question
or