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

Set Row and column span from code behind

23 Answers 307 Views
TileView
This is a migrated thread and some comments may be shown as answers.
Ricardo
Top achievements
Rank 1
Ricardo asked on 06 Aug 2018, 04:30 PM
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

23 Answers, 1 is accepted

Sort by
0
Ricardo
Top achievements
Rank 1
answered on 08 Aug 2018, 11:14 AM

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'

 

 

 

0
Dinko
Telerik team
answered on 09 Aug 2018, 10:04 AM
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.
0
Ricardo
Top achievements
Rank 1
answered on 09 Aug 2018, 03:58 PM

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.

0
Ricardo
Top achievements
Rank 1
answered on 09 Aug 2018, 03:59 PM

Hi Dinko,

 

Sorry, misspelled your name.

0
Dinko
Telerik team
answered on 14 Aug 2018, 12:21 PM
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.
0
Ricardo
Top achievements
Rank 1
answered on 14 Aug 2018, 04:15 PM

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?

0
Ricardo
Top achievements
Rank 1
answered on 14 Aug 2018, 04:19 PM

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>
0
Accepted
Dinko
Telerik team
answered on 17 Aug 2018, 11:38 AM
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.
0
Ricardo
Top achievements
Rank 1
answered on 17 Aug 2018, 02:23 PM

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?

0
Ricardo
Top achievements
Rank 1
answered on 18 Aug 2018, 10:12 AM

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?

0
Dinko
Telerik team
answered on 21 Aug 2018, 01:54 PM
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.
0
Ricardo
Top achievements
Rank 1
answered on 21 Aug 2018, 02:34 PM

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.

0
Ricardo
Top achievements
Rank 1
answered on 21 Aug 2018, 02:54 PM

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.

0
Martin Ivanov
Telerik team
answered on 24 Aug 2018, 10:31 AM
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.
0
Ricardo
Top achievements
Rank 1
answered on 24 Aug 2018, 11:16 AM

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.

 

0
Martin Ivanov
Telerik team
answered on 24 Aug 2018, 12:30 PM
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.
0
Ricardo
Top achievements
Rank 1
answered on 24 Aug 2018, 02:51 PM

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.

0
Martin Ivanov
Telerik team
answered on 27 Aug 2018, 07:16 AM
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.
0
Ricardo
Top achievements
Rank 1
answered on 27 Aug 2018, 09:40 AM

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"">" +

 

 

0
Accepted
Martin Ivanov
Telerik team
answered on 27 Aug 2018, 10:56 AM
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.
0
Ricardo
Top achievements
Rank 1
answered on 27 Aug 2018, 01:07 PM

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?

0
Accepted
Martin Ivanov
Telerik team
answered on 28 Aug 2018, 09:40 AM
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.
0
Ricardo
Top achievements
Rank 1
answered on 28 Aug 2018, 12:40 PM
thanks for the help Martin.
Tags
TileView
Asked by
Ricardo
Top achievements
Rank 1
Answers by
Ricardo
Top achievements
Rank 1
Dinko
Telerik team
Martin Ivanov
Telerik team
Share this question
or