Set Row and column span from code behind

24 posts, 3 answers
  1. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 06 Aug 2018 Link to this post

    Hi,
    I'm following the example provided by telerik in order to develop an application with a radtileview. However, i need to make the items dynamically form the code behind, so my question is how do i define the row and column for each item in the code behind, i.e., similar to what is done in the following example:

         <telerik:RadTileView x:Name="Form" MinimizedItemsPosition="Bottom"
                                 MaximizeMode="Zero"
                                 DragMode="Swap" PreservePositionWhenMaximized="True" Width="700"
                                 RowsCount="{Binding Rows,Mode=TwoWay}"
                                 ColumnsCount="{Binding Columns,Mode=TwoWay}">
                    <telerik:RadTileView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <local:TemplateForm RowsCount="10" ColumnsCount="4" />
                        </ItemsPanelTemplate>
                    </telerik:RadTileView.ItemsPanel>
                   <telerik:RadTileViewItem MinWidth="175" MinHeight="45"
                                             local:TileViewProperties.Row="0"
                                             local:TileViewProperties.Column="0"/>
    </telerik:RadTileViewItem>
    </telerik:RadTileView>

    Can anyone help me?

    Thanks
  2. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 08 Aug 2018 in reply to Ricardo Link to this post

    I have tried:

    TemplateForm templateForm = new TemplateForm
                {
                    RowsCount = 15,
                    ColumnsCount = 3
                };
     
                Form.ItemsPanel.Template = templateForm;

    But I get and error:

    Cannot implicitly convert type 'namespace.TemplateForm' to 'System.Windows.TemplateContent'

     

     

     

  3. Dinko
    Admin
    Dinko avatar
    853 posts

    Posted 09 Aug 2018 Link to this post

    Hi Ricardo,

    What I can suggest is to subscribe to the Loaded event of the custom TileViewPanel. 
    <telerik:RadTileView x:Name="Form" MinimizedItemsPosition="Bottom"
                                 MaximizeMode="Zero"
                                 DragMode="Swap" PreservePositionWhenMaximized="True" Width="700"
                                 RowsCount="{Binding Rows,Mode=TwoWay}"
                                 ColumnsCount="{Binding Columns,Mode=TwoWay}">
                    <telerik:RadTileView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <local:TemplateForm RowsCount="10" ColumnsCount="4" Loaded="customPanel_Loaded" />
                        </ItemsPanelTemplate>
                    </telerik:RadTileView.ItemsPanel>
                   <telerik:RadTileViewItem MinWidth="175" MinHeight="45"
                                             local:TileViewProperties.Row="0"
                                             local:TileViewProperties.Column="0"/>
    </telerik:RadTileView>
    In the loaded event handler, you can get the panel from the sender parameter and applied to a custom property. Then on a button click, for example, you can change the RowsCount and  ColumnsCount properties. Keep in mind that you need to update the layout by calling the InvalidateMeasure() method of the panel.
    public partial class MainWindow : Window
    {
        public TemplateForm myPanel { get; set; }
        public MainWindow()
        {
            InitializeComponent();
        }
     
        private void RadButton_Click(object sender, RoutedEventArgs e)
        {
            myPanel.RowsCount = 15;
            myPanel.ColumnsCount = 3;
            myPanel.InvalidateMeasure();
        }     
     
        private void customPanel_Loaded(object sender, RoutedEventArgs e)
        {
            myPanel = sender as TemplateForm;
        }
    }

    Hope this approach will work in your case.

    Regards,
    Dinko
    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.
  4. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 09 Aug 2018 in reply to Dinko Link to this post

    Hi Dino,

     

    Your solution didn't work, i tried:

    private void customPanel_Loaded(object sender, RoutedEventArgs e)
        {
     
     TemplateForm = new TemplateForm
                {
                    RowsCount = 15,
                    ColumnsCount = 3
                };
     
                TemplateForm.InvalidateMeasure();
     
                TemplateForm = sender as TemplateForm;
        }

    But my template remained with the predefined rows count and columns count.

    I also tried:

    (sender as TemplateForm).RowsCount = 15;
    (sender as TemplateForm).ColumnsCount = 3;
    (sender as TemplateForm).UpdateLayout();

     

    But my template remained with the predefined rows count and columns count.

  5. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 09 Aug 2018 in reply to Ricardo Link to this post

    Hi Dinko,

     

    Sorry, misspelled your name.

  6. Dinko
    Admin
    Dinko avatar
    853 posts

    Posted 14 Aug 2018 Link to this post

    Hi Ricardo,

    Looking at the provided code snippet, there is no need to create a new instance of the TemplateForm. You can just change the value of the RowsCount and ColumnsCount properties without creating a new object. I have modified the RestoredTilesToSpanMultipleRowsAndColumns SDK example in our GitHub repository to demonstrate how you can change these properties runtime. The events handler are located in the MainWindow.xaml.cs file.

    Regards,
    Dinko
    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. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 14 Aug 2018 in reply to Dinko Link to this post

    Hi Dinko,

     

    This solution worked partially, the RadTileView was indeed increased, but when i tried to move an item to a newly created position i got the following error:

    System.IndexOutOfRangeException
      HResult=0x80131508
      Message=Index was outside the bounds of the array.
      Source=MyModule
      StackTrace:
       at RestoredTilesToSpanMultipleRowsAndColumnsTemplateForm.MarkCells(Int32 row, Int32 column, Int32 rowSpan, Int32 columnSpan, Boolean isPopulated) in ...\RestoredTilesToSpanMultipleRowsAndColumns\TemplateForm.cs:line 227
       at ...\RestoredTilesToSpanMultipleRowsAndColumns\MultipleRowsAndColumnsPanel.FixOverlapping(Int32 row, Int32 column, Int32 rowSpan, Int32 columnSpan) in ...\RestoredTilesToSpanMultipleRowsAndColumns\MultipleRowsAndColumnsPanel.cs:line 316
       at ...\RestoredTilesToSpanMultipleRowsAndColumns\MultipleRowsAndColumnsPanel.ItemsOwner_TileDragEnded(Object sender, TileViewDragEventArgs e) in ...\RestoredTilesToSpanMultipleRowsAndColumns\MultipleRowsAndColumnsPanel.cs:line 68

    The Error appear to be in this function:

    private void MarkCells(int row, int column, int rowSpan, int columnSpan, bool isPopulated)
            {
                for (int currentRow = row; currentRow < row + rowSpan; currentRow++)
                {
                    for (int currentColumn = column; currentColumn < column + columnSpan; currentColumn++)
                    {
                        if (currentColumn >= this.ColumnsCount || currentRow >= this.RowsCount)
                        {
                            return;
                        }
                        populatedCells[currentRow, currentColumn] = isPopulated;
                    } // Error stops the progam here
                }
            }

     

    Can you try to move an item on your side to a new empty position to see if the same problem occurs?

  8. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 14 Aug 2018 in reply to Ricardo Link to this post

    The error also occurs if you have the following on the xaml, i.e., if the correct RowsCount and column count aren't already defined at start (i have 1 row and 3 columns, but i tried to define 1/1 and let the template change it when it is loaded, but didn't work):

     

    <telerik:RadTileView x:Name="MyRadGridTileView" DragMode="Swap"
                                     Style="{DynamicResource RadTileViewStyle}" >
                    <telerik:RadTileView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <local:TemplateForm Loaded="customPanel_Loaded" x:Name="customPanel" RowsCount="1" ColumnsCount="1"/>
                        </ItemsPanelTemplate>
                    </telerik:RadTileView.ItemsPanel>
                    <telerik:RadTileViewItem Content="test1" local:TileViewProperties.Row="0" local:TileViewProperties.Column="2"/>
                    <telerik:RadTileViewItem Content="test2" local:TileViewProperties.Row="0" local:TileViewProperties.Column="1"/>
                    <telerik:RadTileViewItem Content="test3" local:TileViewProperties.Row="0" local:TileViewProperties.Column="0"/>
                </telerik:RadTileView>
  9. Answer
    Dinko
    Admin
    Dinko avatar
    853 posts

    Posted 17 Aug 2018 Link to this post

    Hi Ricardo,

    This exception comes from the fact that the SDK  example was not developed for changing the custom panel properties runtime. In order to do it, you need to re-write some of the logic of the custom panel. 

    After an investigation on my side, I manage to found a way to change the custom panel runtime. This way you are setting a new instance of the custom panel. I am attaching a sample project which demonstrates this approach. What I have done is to create a style which targets RadTileView. In this style, I have set the custom TileViewPanel to the ItemsPanel property. Then, for example, I have change this Style with a new one which contains a new custom TileViewPanel with different RowsCount and ColumnsCount properties.

    Regards,
    Dinko
    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.
  10. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 17 Aug 2018 in reply to Dinko Link to this post

    Hi Dinko,

    Your solution worked! Thanks for your help.

    Another question thought, if i want to add items to the radtileview via this template i have to adapt the function:

    private void MultipleRowsAndColumnsPanel_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
            {
                switch (e.Action)
                {
                    case NotifyCollectionChangedAction.Add:
                        break;
                    case NotifyCollectionChangedAction.Move:
                        break;
                    case NotifyCollectionChangedAction.Remove:
                        var removedItem = e.OldItems[0] as RadTileViewItem;
                        var row = TileViewAttachedProperties.GetRow(removedItem);
                        var column = TileViewAttachedProperties.GetColumn(removedItem);
                        var rowSpan = TileViewAttachedProperties.GetRowSpan(removedItem);
                        var columnSpan = TileViewAttachedProperties.GetColumnSpan(removedItem);
     
                        this.MarkCells(row, column, rowSpan, columnSpan, false);
                        this.InvalidateMeasure();
                        break;
                    case NotifyCollectionChangedAction.Replace:
                        break;
                    case NotifyCollectionChangedAction.Reset:
                        break;
                    default:
                        break;
                }
            }

     

    to handle the Add event, correct?

  11. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 18 Aug 2018 in reply to Ricardo Link to this post

    Hi,

    Is there also a way to put the style for the template from the code behind, so that i could change the rows/column dynamically?

    I tried:

     

    Style style = RadGridView.Style;
     
                foreach (Setter styleSetter in style.Setters)
                {
    styleSetter.Property.PropertyType.??  //this goes to ItemsPanel/ItemsPanelTemplate
                }

     

    But i have no idea of how to change the rowscount and columns count.

     

    Can anyone help me?

  12. Dinko
    Admin
    Dinko avatar
    853 posts

    Posted 21 Aug 2018 Link to this post

    Hello Ricardo,

    If I have understood your scenario correctly you want to add items to the RadTileView after you had changed the ItemsPanelTemplate with a new one. If this is the case, you can create RadTileViewItem in code behind and set the Column and Row attached properties. Then you can add the new item to the Items collection of the RadTileView control. Check the following code snippet:
    private void RadButton_Click(object sender, RoutedEventArgs e)
    {
        this.Form.Style = this.Resources["tileViewPanel_2"] as Style;
        RadTileViewItem newItem = new RadTileViewItem() { Content= " New item "};
        TileViewAttachedProperties.SetColumn(newItem,4);
        TileViewAttachedProperties.SetRow(newItem,4);
        this.Form.Items.Add(newItem);
    }

    Regards,
    Dinko
    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.
  13. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 21 Aug 2018 in reply to Dinko Link to this post

    Hi Dinko,

     

    More or less, yes.

     

    I need to do 2 things:

     

    1. set the rows count and columns count dynamically.

    2. Add the item without specifying the row/column, i.e, just by doing :

    this.Form.Style = this.Resources["tileViewPanel_2"] as Style;
        RadTileViewItem newItem = new RadTileViewItem() { Content= " New item "};
        TileViewAttachedProperties.SetColumnSpan(newItem,4);
        TileViewAttachedProperties.SetRowSpan(newItem,4);
        this.Form.Items.Add(newItem);

     

    The form should be able to detect the free grid cells in order to span the item.

  14. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 21 Aug 2018 in reply to Ricardo Link to this post

    Hi Dinko,

     

    The solution needs to be altered to this:

    this.Form.Style = null;
        RadTileViewItem newItem = new RadTileViewItem() { Content= " New item "};
        TileViewAttachedProperties.SetColumn(newItem,4);
        TileViewAttachedProperties.SetRow(newItem,4);
        this.Form.Items.Add(newItem);
    this.Form.Style = this.Resources["tileViewPanel_2"] as Style

     

    otherwise the last item won't be drawn.

  15. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2062 posts

    Posted 24 Aug 2018 Link to this post

    Hello Ricardo,

    Creating an ItemsPanelTemplate in code could be a bit tricky. To achieve your requirement you can use define the ItemsPanelTemplate as a string and when you need it create the template instance using the XamlReader.Parse() method. This will allow you to define the rows and columns in the string before parse it. Here is an example in code:
    private void RadButton_Click(object sender, RoutedEventArgs e)
    {
        this.tileView.Style = CreateTileViewStyle(5, 5);
    }   
     
    private static Style CreateTileViewStyle(int rowsCount, int columnsCount)
    {
        Style style = new Style(typeof(RadTileView));
        ItemsPanelTemplate panel = CreatePanel(rowsCount, columnsCount);
        style.Setters.Add(new Setter(RadTileView.ItemsPanelProperty, panel));
        return style;
    }
     
    private static ItemsPanelTemplate CreatePanel(int rowsCount, int columnsCount)
    {
        string panelString = @"<ItemsPanelTemplate  xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"" xmlns:local=""clr-namespace:RestoredTilesToSpanMultipleRowsAndColumns;assembly=RestoredTilesToSpanMultipleRowsAndColumns"">" +
                                    @"<local:MultipleRowsAndColumnsPanel RowsCount=""" + rowsCount + @""" ColumnsCount=""" + columnsCount + @""" />" +
                              "</ItemsPanelTemplate>";
        ItemsPanelTemplate panel =  (ItemsPanelTemplate)XamlReader.Parse(panelString);
        return panel;
    }
    Note that the xmlns that points to the project's namespace (xmlns:local) should have set the "assembly" parameter (assembly=RestoredTilesToSpanMultipleRowsAndColumns). Otherwise, the parser won't be able to create the ItemsPanelTemplate and an exception will be thrown.

    I've also updated and attached Dinko's project to show this approach. I hope this helps.

    Regards,
    Martin Ivanov
    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.
  16. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 24 Aug 2018 in reply to Martin Ivanov Link to this post

    Thanks Martin,

    I copied the new MultiRowsAndColumnsPanel to my project, but when i ran it, i got the following error:

     

    System.Windows.Markup.XamlParseException: ''Set property 'System.Windows.FrameworkTemplate.Template' threw an exception.' Line number '1' and line position '280'.'

    Inner Exception:

    ArgumentNullException: Key cannot be null.

     

  17. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2062 posts

    Posted 24 Aug 2018 Link to this post

    Hi Ricardo,

    To resolve this error you will need to change the "assembly" attribute of the "xmlns:local" namespace in the string. The "assembly" attribute should contain the assembly name of your project. For example: xmlns:local=""clr-namespace:TheNameSpaceWhereTheCustomPanelIsDefined;assembly=MyAssemblyNameHere""

    Regards,
    Martin Ivanov
    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.
  18. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 24 Aug 2018 in reply to Martin Ivanov Link to this post

    I moved the class into my namespace, but it still doesn't seem to work:

    Structure:

    Namespace

    - Folder

      - Multicolumns

    Code:

    namespace MyNameSpace.Multicolumns
    {
        public class Multicolumns : TileViewPanel, INotifyPropertyChanged
     
    ....
    }

     

    In code call:

    string panelString = @"<ItemsPanelTemplate
    xmlns:local=""clr-namespace:MyNameSpace.Multicolumns;assembly=MultiColumns"">" +
    @"<local:MultiColumns RowsCount=""" + rowsCount + @""" ColumnsCount=""" + columnsCount + @""" />" +
    "</ItemsPanelTemplate>";

    but i always get the error that the Key cannot be null.

  19. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2062 posts

    Posted 27 Aug 2018 Link to this post

    Hi,

    You will also need to add the main namespace in order to parse the ItemsPanelTemplate.

    I hope this helps.

    Regards,
    Martin Ivanov
    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.
  20. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 27 Aug 2018 in reply to Martin Ivanov Link to this post

    It is still not working :(.

    @"<ItemsPanelTemplate
                                   xmlns =""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
               xmlns:local=""clr-namespace:MyNamespace.Folder;assembly=MyNamespace.Folder"">" +
                                   @"<local:TemplateForm RowsCount=""" + rowsCount + @""" ColumnsCount=""" + columnsCount + @""" />" +
                                     "</ItemsPanelTemplate>";

     

    I have no idea what i'm doing wrong.

     

    The error is still:

     

    System.Windows.Markup.XamlParseException: ''Set property 'System.Windows.FrameworkTemplate.Template' threw an exception.' Line number '3' and line position '158'.'
     
    Inner Exception:
     
    ArgumentNullException: Key cannot be null.

     

    The line he is complaining about is:

    xmlns:local=""clr-namespace:MyNamespace.Folder;assembly=MyNamespace.Folder"">" +

     

     

  21. Answer
    Martin Ivanov
    Admin
    Martin Ivanov avatar
    2062 posts

    Posted 27 Aug 2018 Link to this post

    Hello Ricardo,

    From the last code snippets it seems that the namespace used in the template string doesn't match the namespace of the converter in the code. Note that the namespaces are case sensitive. The local namespace in the code states "namespace MyNameSpace.Multicolumns", with a big 'S' in the word "MyNameSpace". But the one defined in the string is "MyNamespace" with a small 'S' letter. Also, the 'assembly' attribute should match the assembly name of the application. You can see this if you right click on the project and select Properties from the context menu. See the following picture.

    Can you try match those and let me know how it goes?

    Regards,
    Martin Ivanov
    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.
  22. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 27 Aug 2018 in reply to Martin Ivanov Link to this post

    Thanks Martin, my problem was the assembly name that was incorrect.

     

    I got another question though, is it possible to add items to this template without giving the row/column, i.e., only giving the rowspan and columnspan and let the template determine where to put the item?

  23. Answer
    Martin Ivanov
    Admin
    Martin Ivanov avatar
    2062 posts

    Posted 28 Aug 2018 Link to this post

    Hello Ricardo,

    This type of layout won't work properly without knowing the element's row and column. It behaves like a native Grid - if you don't set the row and column of the element, it will be positioned on 0,0. In general it is not very clear where the item should be drawn without its row and column setting. I guess in your case you want some kind of automatic layout based on the items in the source and how much space the require. It would be possible to achieve this, but the custom MultipleRowsAndColumnsPanel panel doesn't have such code. In order to achieve your goal you will need to clear out your requirement and implement it in the MultipleRowsAndColumnsPanel class. 

    Regards,
    Martin Ivanov
    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.
  24. Ricardo
    Ricardo avatar
    44 posts
    Member since:
    May 2018

    Posted 28 Aug 2018 in reply to Martin Ivanov Link to this post

    thanks for the help Martin.
Back to Top