VirtualGrid row of custom cells

8 posts, 2 answers
  1. Yuri
    Yuri avatar
    12 posts
    Member since:
    Jun 2011

    Posted 23 Jan 2019 Link to this post

    Hi,

    I'm trying to create row of check boxes. To do that I created custom cell element as described in the topic https://docs.telerik.com/devtools/winforms/controls/virtualgrid/cells/creating-custom-cells.

    But after form resizing custom cells are displayed in wrong row.

    Please find screenshot attached.

    Is it a working way to implement row of custom cells in VirtualGrid?

    Thank you in advance.

  2. Hristo
    Admin
    Hristo avatar
    1520 posts

    Posted 24 Jan 2019 Link to this post

    Hello Yuri,

    The UI building the RadVirtualGrid control is also virtualized, basically meaning that the visual elements are reused while scrolling. The screenshots indicate that custom cell is being used in a column in which it is not intended. Can you please check the IsCompatible method in the custom cell class in your project and make sure that it returning true only for the desired column. In case the issue persists, please share a code snippet demonstrating the result on your end so that I can test it.

    I hope this will help.

    Regards,
    Hristo
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  3. Yuri
    Yuri avatar
    12 posts
    Member since:
    Jun 2011

    Posted 24 Jan 2019 Link to this post

    Hi Hristo,

    Thank you for your reply.

    I took a look on IsCompatible method. And it works fine for me. But issue still exists.

    I would like to share a code snippet with you.

    //Custom cell implementation
    public class VirtualGridCheckBoxCellElement : VirtualGridCellElement
    {
        public event IsCompatibleEventHandler IsCompatibleCell;
     
        protected override void CreateChildElements()
        {
            base.CreateChildElements();
     
            checkBox = new RadCheckBoxElement();
            Children.Add(checkBox);
        }
     
        public override bool IsCompatible(int data, object context)
        {
            if (context is VirtualGridRowElement rowElement)
            {
                var args = new IsCompatibleEventArgs(data, rowElement);
                IsCompatibleCell?.Invoke(this, args);
                 
                return args.IsCompatible;
            }
     
            return false;
        }
     
        private RadCheckBoxElement checkBox;
    }
     
    public delegate void IsCompatibleEventHandler(object caller, IsCompatibleEventArgs args);
     
    public class IsCompatibleEventArgs : EventArgs
    {
        public int ColumnIndex { get; }
        public VirtualGridRowElement RowElement { get; }
        public bool IsCompatible { get; set; }
     
        internal IsCompatibleEventArgs(int columnIndex, VirtualGridRowElement rowElement)
        {
            ColumnIndex = columnIndex;
            RowElement = rowElement;
        }
    }
    //usage
    private void VirtualGrid_CreateCellElement(object sender, VirtualGridCreateCellEventArgs e)
    {
        if (IsCheckBoxCompatibleCell(e.RowIndex, e.ColumnIndex))
        {
            var checkBoxCellElement = new VirtualGridCheckBoxCellElement();
     
            checkBoxCellElement.IsCompatibleCell += (o, args) =>
            {
                args.IsCompatible = IsCheckBoxCompatibleCell(args.RowElement.RowIndex, args.ColumnIndex);
            };
     
            e.CellElement = checkBoxCellElement;
        }
    }
     
    public bool IsCheckBoxCompatibleCell(int rowIndex, int columnIndex)
    {
        return columnIndex >= 0 && rowIndex == 33;
    }

     

    Used version of controls is 2017.1.221.40. Maybe this is a reason...

    Thank you, Yuri

  4. Answer
    Hristo
    Admin
    Hristo avatar
    1520 posts

    Posted 25 Jan 2019 Link to this post

    Hello Yuri,

    Looking at the code snippet and the screenshot, it appears that you are trying to create a custom cell only for a particular row and column in the grid. This way the grid ends up with different cells located in the same column. Because of reusing the elements, this leads to the described behavior. Please note that this is not supported and if you need custom cells, you will need to use them for the entire column. Then the IsCompatible method should only return true if the column index is the one you have specified and the row is data row.

    As a possible solution, you can try creating a custom cell having different elements in it. This way you will be able to display one element inside the cell for some rows and other elements for other rows. I am attaching my test project demonstrating the suggested approach as well as a short video showing the result on my end.

    Regards,
    Hristo
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  5. Yuri
    Yuri avatar
    12 posts
    Member since:
    Jun 2011

    Posted 28 Jan 2019 in reply to Hristo Link to this post

    Hi Hristo,

    Thank you for you reply.

    I have tried your solution, but it slows down my grid where commonly displayed over 200 columns.
    And I finished with another solution. It works for me fine. 

    I would like to share it. Could you please take a look and answer if you see something wrong?

    private void virtualGrid_CellFormatting(object sender, VirtualGridCellElementEventArgs e)
    {
        if (e.CellElement.RowIndex < 0 || e.CellElement.RowIndex >= virtualGrid.RowCount || e.CellElement is VirtualGridIndentCellElement)
        {
            return;
        }
         
        if (e.CellElement.Value is bool)
        {
            MakeCheckBoxCell(e.CellElement);
        }
        else
        {
            RestoreNormalCell(e.CellElement);
        }
    }
     
    private void MakeCheckBoxCell(VirtualGridCellElement cellElement)
    {
        if (cellElement.Children.Any())
        {
            cellElement.Children.Clear();
        }
         
        cellElement.Children.Add(InitCheckBox(cellElement));
        cellElement.DrawText = false;
    }
     
    private void RestoreNormalCell(VirtualGridCellElement cellElement)
    {
        cellElement.Children.Clear();
        cellElement.ResetValue(LightVisualElement.DrawTextProperty, ValueResetFlags.Local);
    }
     
    private RadCheckBoxElement InitCheckBox(VirtualGridCellElement cellElement)
    {
        var newCheckBoxElement = new RadCheckBoxElement
        {
            Checked = (bool) cellElement.Value,
            CheckAlignment = ContentAlignment.MiddleCenter
        };
     
        newCheckBoxElement.CheckStateChanged += (o, e) =>
        {
            timetableGrid.VirtualGridElement.SetCellValue(newCheckBoxElement.Checked, cellElement.RowIndex,
                cellElement.ColumnIndex, cellElement.ViewInfo);
     
            timetableGrid.SelectCell(cellElement.RowIndex, cellElement.ColumnIndex);
        }
     
        return newCheckBoxElement;
    }
  6. Answer
    Hristo
    Admin
    Hristo avatar
    1520 posts

    Posted 29 Jan 2019 Link to this post

    Hello Yuri,

    Generally speaking, you need to be careful when instantiating objects in the CellFormating event. This event will be raised numerous times while running the application and initializing objects in it may increase the consumed memory. Otherwise, I see no other issues with your approach. You can consider caching the elements so that new RadCheckBoxElement objects are created for new rows which are raising the formatting event. In order to update the toggle state of the checkbox, I also had to use a flag and suspend the formatting. Please check my code snippet below: 
    bool suspenFormatting;
    Dictionary<int, RadCheckBoxElement> checkElements = new Dictionary<int, RadCheckBoxElement>();
     
    private void RadVirtualGrid1_CellFormatting(object sender, VirtualGridCellElementEventArgs e)
    {
        if (this.suspenFormatting || e.CellElement.RowIndex < 0 || e.CellElement.RowIndex >= this.radVirtualGrid1.RowCount || e.CellElement is VirtualGridIndentCellElement)
        {
            return;
        }
     
        if (e.CellElement.Value is bool)
        {
            MakeCheckBoxCell(e.CellElement);
        }
        else
        {
            RestoreNormalCell(e.CellElement);
        }
    }
     
    private void MakeCheckBoxCell(VirtualGridCellElement cellElement)
    {
        if (cellElement.Children.Any())
        {
            cellElement.Children.Clear();
        }
     
        cellElement.Children.Add(InitCheckBox(cellElement));
        cellElement.DrawText = false;
    }
     
    private void RestoreNormalCell(VirtualGridCellElement cellElement)
    {
        cellElement.Children.Clear();
        cellElement.ResetValue(LightVisualElement.DrawTextProperty, ValueResetFlags.Local);
    }
     
    private RadCheckBoxElement InitCheckBox(VirtualGridCellElement cellElement)
    {
        RadCheckBoxElement checkElement = null;
        if (!checkElements.ContainsKey(cellElement.RowIndex))
        {
            checkElement = new RadCheckBoxElement();
            checkElements.Add(cellElement.RowIndex, checkElement);
        }
        else
        {
            checkElement = checkElements[cellElement.RowIndex];
        }
     
        checkElement.CheckStateChanged -= checkElement_CheckStateChanged;
        checkElement.Checked = (bool)cellElement.Value;
        checkElement.CheckAlignment = ContentAlignment.MiddleCenter;
        checkElement.CheckStateChanged += checkElement_CheckStateChanged;
     
        return checkElement;
    }
     
    private void checkElement_CheckStateChanged(object sender, EventArgs e)
    {
        this.suspenFormatting = true;
        RadCheckBoxElement checkElement = (RadCheckBoxElement)sender;
        VirtualGridCellElement cellElement = checkElement.Parent as VirtualGridCellElement;
     
        this.radVirtualGrid1.VirtualGridElement.SetCellValue(checkElement.Checked, cellElement.RowIndex,
                cellElement.ColumnIndex, cellElement.ViewInfo);
     
        this.radVirtualGrid1.SelectCell(cellElement.RowIndex, cellElement.ColumnIndex);
     
        this.suspenFormatting = false;
    }

    I hope this will help. Let me know if you need further assistance.

    Regards,
    Hristo
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
  7. Yuri
    Yuri avatar
    12 posts
    Member since:
    Jun 2011

    Posted 30 Jan 2019 in reply to Hristo Link to this post

    Hi Hristo,

    Thank you very much for your reply, it worka for me perfect!

    With the best regards, Yuri.

  8. Hristo
    Admin
    Hristo avatar
    1520 posts

    Posted 30 Jan 2019 Link to this post

    Hello Yuri,

    Thank you for the update. I am glad that the discussed approach is working well on your end. Let me know if you need further assistance.

    Regards,
    Hristo
    Progress Telerik
    Get quickly onboarded and successful with your Telerik and/or Kendo UI products with the Virtual Classroom free technical training, available to all active customers. Learn More.
Back to Top