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

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'
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
>
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

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.

Hi Dinko,
Sorry, misspelled your name.
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

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?

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

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?

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?
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

Hi Dinko,
More or less, yes.
I need to do 2 things:
- 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.

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.
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;
}
I've also updated and attached Dinko's project to show this approach. I hope this helps.
Regards,
Martin Ivanov
Progress Telerik

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.
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

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.
You will also need to add the main namespace in order to parse the ItemsPanelTemplate.
I hope this helps.
Regards,
Martin Ivanov
Progress Telerik

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

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?
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
