Toolroom Tech Blog

Devlopers Digest

Fix by Rewrite for XAML ScrollViewer issue

How to fix strange scrolling behavior within a Windows Phone Pivot by rewriting a few lines of XAML 1:1 :)

Yesterday I had the strangest XAML behaviour ever ... I have to share this!

The issue 

In a Windows Phone app I have this object tree in my ApplicationPage, where each View contains a ScrollViewer with simple Grid content - nothing special.

<Grid x:Name="LayoutRoot">
	<controls:Pivot Title="{Binding PageTitle}">
		<controls:PivotItem Header="Page 1">
			<Grid>
				<Views:ItemOneView DataContext="{Binding Data}"/>
			</Grid>
		</controls:PivotItem>
		<controls:PivotItem Header="Page 2">
			<Grid>
				<Views:ItemTwoView DataContext="{Binding Data}"/>
			</Grid>
		</controls:PivotItem>
		<controls:PivotItem Header="Page 3">
			<Grid>
				<Views:ItemThreeView DataContext="{Binding Data}"/>
			</Grid>
		</controls:PivotItem>
	</controls:Pivot>
</Grid>

The issue was, that the runtime didn't allow me to scroll down to hidden content of ItemTwoView. The scrollbar didn't come up and altough I saw the content while scrolling, it moved back to the original position when I stopped.

The fix

After hours of debugging, I just rewrote the 5 lines from <controls:PivotItem Header="Page 2"> to </controls:PivotItem> exactly 1:1. And it worked!

I really didn't believe it ... so I pushed undo and had the behavior again, although the code didn't change. Hidden characters? Encoding issue? Bug? Don't know.

Properly adding UIElements from code

Although it's not the way how you should design your WPF applications, you may try to add UIElements at runtime from code behind. Therefore you should introduce the recently added elements into the XAML namescope. Otherwise you will not be able to find the added item  again and you may run in troubles with animation storyboards, since they use runtime name lookups with their key property "TargetName".

In the sample below, a row with a label and a textbox is added to a grid at runtime:

private void AddParam(int rowId, string labelText, string displayValue)
{
	grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });

	var label = new Label { Content = labelText };
	label.SetValue(Grid.RowProperty, rowId);
	label.SetValue(Grid.ColumnProperty, 0);
	grid.Children.Add(labelO);

	var textboxName = string.Format("dauerPosParam{0}__O", rowId);
	var textbox = new TextBox { Text = displayValue, Name = textboxName };
	textbox.SetValue(Grid.RowProperty, rowId);
	textbox.SetValue(Grid.ColumnProperty, 1);
	grid.Children.Add(textbox);
	if(FindName(textboxName) == null)
		RegisterName(textboxName, textbox);
}

Get further Information at FrameworkElement.RegisterName or NameScope.RegisterName.