Problem summary: code-behind positioning is ignored if some tiles are collapsed unless a delay is introduced.
I have 12 tiles in 2 columns, all in restored state.
When all have their visibility set to visible I can set the position in the constructor of the hosting usercontrol and it works.
However if some of the tiles are collapsed, then the positioning is ignored (it seems) unless I introduce a delay of about 1/2 sec.
I tried putting the positioning code in the usercontrol loaded event, and even in the tileview loaded event, with no improvement.
It seems that if tiles with a position prior the ones being positioned are collapsed the problem occurs.
I noticed that if the position of the 12 tiles are defined in xaml as 0,1,2,3,4,5,6,7,8,9,10,11, that is, in order, then when tiles 2..6 are set to collapsed then the position order at run time is 0,1,2,2,2,2,2,2,3,4,5,6. So the collapsed tiles all have a position of 2, and tile 7 has a position of 2, 8-3, and so on.
When I set the position I only position visible tiles, and then with the position index starting with 0 and ending with visible_count-1, like in the 2nd set of position orders above. I do not set the positions in order of position but rather in order of occurrence, that is for example I iterate through the tile list and set the position of item 0 to 3, item 1 to 0, item 2 to 2, and so on.
I have IsItemsAnimationEnabled = False and PreservePositiojnWhenMaximized=True
I'm giving you all this info because I don't know what is relevant and what is not. Again, if I introduce a timer delay the tiles position properly.
10 Answers, 1 is accepted
Additional Info:
After positioning and the display shows the incorrect position, an inspection of the position values shows the correct position. So the tiles think they are in the correct position, so it looks like a screen update problem? I tried doing a tileview.updatelayout and a layoutroot.updateloayout with no success.
Also a delay as small as 100ms is enough to have the control render correctly, but of course this is not ideal.
Is there a way to force the control to redraw?
Is there an event that fires when the control can accept re-positioning?
I will need some time to check on your scenario. I will contact you as soon as I have more information on the matter.
Regards,
Martin
Telerik
I am not sure that I completely understand your case. This is why I would ask you to send me a runnable code that demonstrates your implementation and the position change with the 1/2 sec delay behavior, so I can test it locally and get better understanding of your scenario.
About the event related to positioning you can use TilesPositionChanged event. As for redrawing the control you can try to call its UpdateLayout() method in the tileview's TilesPositionChanged event handler. You can also try to call the Measure() and Arrange() methods before the UpdateLayout().
Regards,
Martin
Telerik
I have a sample app for you to look at but I don't know how to upload the zip file, it gives error only jpg, gif...etc
So posting here
Here is the xaml
<
UserControl
xmlns:telerik
=
"http://schemas.telerik.com/2008/xaml/presentation"
x:Class
=
"TelerikTileViewTest.MainPage"
mc:Ignorable
=
"d"
d:DesignHeight
=
"400"
d:DesignWidth
=
"800"
>
<
Grid
x:Name
=
"LayoutRoot"
Background
=
"White"
>
<
telerik:RadTileView
Name
=
"TileView"
>
<
telerik:RadTileViewItem
Name
=
"Tile1"
Header
=
"Tile 1"
>
<
TextBlock
Text
=
"Tile 1 Content"
/>
</
telerik:RadTileViewItem
>
<
telerik:RadTileViewItem
Name
=
"Tile2"
Header
=
"Tile 2"
>
<
TextBlock
Text
=
"Tile 2 Content"
/>
</
telerik:RadTileViewItem
>
<
telerik:RadTileViewItem
Name
=
"Tile3"
Header
=
"Tile 3"
>
<
TextBlock
Text
=
"Tile 3 Content"
/>
</
telerik:RadTileViewItem
>
<
telerik:RadTileViewItem
Name
=
"Tile4"
Header
=
"Tile 4"
>
<
TextBlock
Text
=
"Tile 4 Content"
/>
</
telerik:RadTileViewItem
>
<
telerik:RadTileViewItem
Name
=
"Tile5"
Header
=
"Tile 5"
>
<
TextBlock
Text
=
"Tile 5 Content"
/>
</
telerik:RadTileViewItem
>
</
telerik:RadTileView
>
</
Grid
>
</
UserControl
>
here is the code behing
Partial
Public
Class
MainPage
Inherits
UserControl
Private
TileTimer
As
New
Windows.Threading.DispatcherTimer
'sample showing that tile positioning is not honored in code behind in ctor or loaded
'however introducing a slight delay (100 ms in this case) does re-position tiles
'in xaml position is : 1 2 3 4 5
'desired position is : 2 1 3 4 5
Public
Sub
New
()
InitializeComponent()
TileView.IsItemsAnimationEnabled =
False
TileView.PreservePositionWhenMaximized =
True
TileView.IsItemsAnimationEnabled =
False
TileView.IsVirtualizing =
False
TileTimer =
New
Windows.Threading.DispatcherTimer
TileTimer.Interval = TimeSpan.FromMilliseconds(100)
AddHandler
TileTimer.Tick,
AddressOf
tileTimer_Tick
Tile2.Position = 0
'this is not honored
End
Sub
Private
Sub
MainPage_Loaded(sender
As
Object
, e
As
System.Windows.RoutedEventArgs)
Handles
Me
.Loaded
Tile2.Position = 0
'this is not honored
TileTimer.Start()
End
Sub
Private
Sub
tileTimer_Tick(sender
As
Object
, e
As
EventArgs)
TileTimer.
Stop
()
Tile2.Position = 0
'this is honored
End
Sub
End
Class
Addendum: Visibility/Collapsed of individual tiles does not have anything to do with recreating the problem as I first thought. Is seem that while the control is initializing it is ignoring tile positioning from code behind, once it is fully initialized everything works as expected. My problem is I don't know when it is done 'initializing'. I have animation off so annimationcompleted never fires. TilePositionChanged does fire, once for each tile on load, so this code does work, but it is only a slight improvement over the timer, in that I need to know the order the tiles load and move tiles only after they have been initially positioned.
Private
Sub
TileView_TilePositionChanged(sender
As
Object
, e
As
Telerik.Windows.RadRoutedEventArgs)
Handles
TileView.TilePositionChanged
System.Diagnostics.Debug.WriteLine(
DirectCast
(e.Source, Telerik.Windows.Controls.RadTileViewItem).Name)
If
DirectCast
(e.Source, Telerik.Windows.Controls.RadTileViewItem).Name =
"Tile3"
Then
If
_firstTime
Then
_firstTime =
False
Tile2.Position = 0
'this is honored
End
If
End
If
End
Sub
Here is my solution, it's not terrible. Maintain a flag indicating first time initialization is in progress. Once the last tile in xaml is positioned then set tiles to desired position and turn off flag
code
Partial
Public
Class
MainPage
Inherits
UserControl
'in xaml position is : 1 2 3 4 5
'desired position is : 2 1 3 4 5
Private
_firstTime
As
Boolean
=
True
Public
Sub
New
()
InitializeComponent()
End
Sub
Private
Sub
LastTile_PositionChanged(sender
As
Object
, e
As
Telerik.Windows.RadRoutedEventArgs)
If
_firstTime
Then
_firstTime =
False
Tile2.Position = 0
'this is not honored
End
If
End
Sub
End
Class
xaml
<
UserControl
xmlns:telerik
=
"http://schemas.telerik.com/2008/xaml/presentation"
x:Class
=
"TelerikTileViewTest.MainPage"
mc:Ignorable
=
"d"
d:DesignHeight
=
"400"
d:DesignWidth
=
"800"
>
<
Grid
x:Name
=
"LayoutRoot"
Background
=
"White"
>
<
telerik:RadTileView
Name
=
"TileView"
IsItemsAnimationEnabled
=
"False"
PreservePositionWhenMaximized
=
"True"
>
<
telerik:RadTileViewItem
Name
=
"Tile1"
Header
=
"Tile 1"
>
<
TextBlock
Text
=
"Tile 1 Content"
/>
</
telerik:RadTileViewItem
>
<
telerik:RadTileViewItem
Name
=
"Tile2"
Header
=
"Tile 2"
>
<
TextBlock
Text
=
"Tile 2 Content"
/>
</
telerik:RadTileViewItem
>
<
telerik:RadTileViewItem
Name
=
"Tile3"
Header
=
"Tile 3"
>
<
TextBlock
Text
=
"Tile 3 Content"
/>
</
telerik:RadTileViewItem
>
<
telerik:RadTileViewItem
Name
=
"Tile4"
Header
=
"Tile 4"
>
<
TextBlock
Text
=
"Tile 4 Content"
/>
</
telerik:RadTileViewItem
>
<
telerik:RadTileViewItem
Name
=
"Tile5"
Header
=
"Tile 5"
PositionChanged
=
"LastTile_PositionChanged"
>
<
TextBlock
Text
=
"Tile 5 Content"
/>
</
telerik:RadTileViewItem
>
</
telerik:RadTileView
>
</
Grid
>
</
UserControl
>
Thank you for the code snippets. I can confirm that the tileview items' Position setting is not respected until the tiles are generated. This behavior in RadTileView is expected since the position setting requires the item to has its ParentTileView set which happens on the tile's generation.
In order to set the Position of a specific item on load of the control you can use couple approaches:
- Subscribe for the RadTileView's Loaded event and set the tile's Position in Dispatcher.
Private
Sub
TileView_Loaded(sender
As
Object
, e
As
RoutedEventArgs)
Dispatcher.BeginInvoke(
New
Action(
Function
()
Me
.Tile2.Position = 0
End
Function
))
End
Sub
- Or you can subscribe for the StatusChanged event of the ItemContainerGenerator of the tileview and listen for the "ContainersGenerated" status. If the containers are generated set the position.
' subscribe for the Me.TileView.ItemContainerGenerator's StatusChanged event
'---------------------------------
Private
Sub
ItemContainerGenerator_StatusChanged(sender
As
Object
, e
As
EventArgs)
Dim
generator
As
ItemContainerGenerator = TryCast(sender, ItemContainerGenerator)
If
generator.Status = System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated
Then
Me
.Tile2.Position = 0
End
If
End
Sub
Please try this and let me know if it works for you.
Regards,
Martin
Telerik