I am adding radexpander elements to a scrollviewer control on runtime. Suppose the last expander element is located right at the bottom of the scrollviewer's viewport.My requirement is that when the user expands that particular radexpander element, the scrollviewer should move downwards so that the expander's content gets visible which as of now goes beyond the scrollviewer's viewport and the user has to manually scroll down to see the content.
11 Answers, 1 is accepted
When the last expander expands, you can use ScrollViewer's ScrollToVerticalOffset method. Also, take a look at this StackOverflow thread as it explains how make the Silverlight ScrollViewer scroll to show a child control with focus?
Let me know if need further assistance.
On a side note, I'd like to inform you that we've just released an online tool that allows you to reduce the size of your Silverlight applications. For more information, please visit http://blogs.telerik.com/blogs/posts/10-06-10/telerik_assembly_minifier.aspx
Kind regards,
Kiril Stanoev
the Telerik team
Please find attached a sample project demonstrating one possible solution to this scenario.
Best wishes,
Kiril Stanoev
the Telerik team
Thanks for the solution. Its working much better now. But its slightly inconsistent. As in, the scrollviewer position gets updated for later layout updates (especially for the last elements in the extent) but its not the case during the first layout update for them.
Do you find the usage of a Dispatcher inconsistent? If so, the Dispatcher is necessary since the StackPanel that holds the Expanders has not yet updated its height. If you change the expanded event handler to the one bellow you will see that 2 different values appear:
void
expander_Expanded(
object
sender, RoutedEventArgs e)
{
RadExpander expander = sender
as
RadExpander;
GeneralTransform expanderTransform = expander.TransformToVisual(scrollViewer1);
Rect rectangle = expanderTransform.TransformBounds(
new
Rect(
new
Point(expander.Margin.Left, expander.Margin.Top), expander.RenderSize));
double
newOffset = scrollViewer1.VerticalOffset + ((rectangle.Bottom + 100) - scrollViewer1.ViewportHeight);
var before = (scrollViewer1.Content
as
StackPanel).ActualHeight;
MessageBox.Show(
"Before dispatcher: "
+ before);
Dispatcher.BeginInvoke(() =>
{
var after = (scrollViewer1.Content
as
StackPanel).ActualHeight;
MessageBox.Show(
"Before dispatcher: "
+ after);
scrollViewer1.ScrollToVerticalOffset(newOffset);
});
}
Best wishes,
Kiril Stanoev
the Telerik team
Unfortunately I am not able to reproduce the issue. Could you please send me a sample project demonstrating the problem. This way I will be better able to assist you.
All the best,
Kiril Stanoev
the Telerik team
Imports
System
Imports
System.Collections.Generic
Imports
System.Linq
Imports
System.Windows
Imports
System.Windows.Controls
Imports
System.Windows.Documents
Imports
System.Windows.Input
Imports
System.Windows.Media
Imports
System.Windows.Media.Animation
Imports
System.Windows.Shapes
Imports
System.Windows.Navigation
Imports
TDSolsticeSKUSelector.SKUSelectorProxy
Imports
System.Windows.Data
Imports
System.Windows.Browser
Imports
Telerik.Windows.Controls
Imports
System.Windows.Controls.ToolKit
Imports
System.ServiceModel
Partial
Public Class StartScreen
Inherits UserControl
Dim newOffset As FrameworkElement
Public Sub New()
InitializeComponent()
AddExpander()
End Sub
Private Sub UpdateScroller()
' MessageBox.Show(expStack.ActualHeight)
expSV.ScrollIntoView(newOffset)
End Sub
Private Sub expanderPanel_Collapsed(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
AddHandler expSV.LayoutUpdated, AddressOf expSV_LayoutUpdated
End Sub
Private Sub expanderPanel_Expanded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs)
AddHandler expSV.LayoutUpdated, AddressOf expSV_LayoutUpdated
End Sub
Private Sub AddExpander()
For i As Integer = 0 To 10
Dim expanderPanel As New RadExpander
AddHandler expanderPanel.Expanded, AddressOf expanderPanel_Expanded
AddHandler expanderPanel.Collapsed, AddressOf expanderPanel_Collapsed
Telerik.Windows.Controls.Animation.AnimationManager.SetIsAnimationEnabled(expanderPanel,
True)
Telerik.Windows.Controls.Animation.AnimationManager.AnimationSpeedRatio = 0.35
Dim grdHeader As Grid = New Grid()
Dim column0 As New ColumnDefinition
column0.Width =
New GridLength(25)
grdHeader.ColumnDefinitions.Add(column0)
Dim column1 As New ColumnDefinition
column1.Width =
New GridLength(250)
grdHeader.ColumnDefinitions.Add(column1)
Dim column2 As New ColumnDefinition
column2.Width =
New GridLength(5)
grdHeader.ColumnDefinitions.Add(column2)
Dim column3 As New ColumnDefinition
column3.Width =
New GridLength(330)
grdHeader.ColumnDefinitions.Add(column3)
Dim column4 As New ColumnDefinition
column4.Width =
New GridLength(55)
grdHeader.ColumnDefinitions.Add(column4)
Dim column5 As New ColumnDefinition
column5.Width =
New GridLength(75)
grdHeader.ColumnDefinitions.Add(column5)
Dim txtComName As New TextBlock
txtComName.TextAlignment = TextAlignment.Center
txtComName.FontWeight = FontWeights.Bold
txtComName.Foreground =
New SolidColorBrush(Colors.Black)
txtComName.TextWrapping = TextWrapping.Wrap
txtComName.Text =
"Company" + Convert.ToString(i)
txtComName.SetValue(Grid.ColumnProperty, 1)
grdHeader.Children.Add(txtComName)
Dim txtPart2 As New TextBlock
txtPart2.Foreground =
New SolidColorBrush(Colors.Black)
txtPart2.Text =
"|"
txtPart2.SetValue(Grid.ColumnProperty, 2)
grdHeader.Children.Add(txtPart2)
Dim txtContName As New TextBlock
txtContName.TextAlignment = TextAlignment.Center
txtContName.FontWeight = FontWeights.Bold
txtContName.Foreground =
New SolidColorBrush(Colors.Black)
txtContName.TextWrapping = TextWrapping.Wrap
txtContName.Text =
"ContactName" + Convert.ToString(i)
txtContName.SetValue(Grid.ColumnProperty, 3)
grdHeader.Children.Add(txtContName)
Dim txtPart4 As New TextBlock
txtPart4.Foreground =
New SolidColorBrush(Colors.Black)
txtPart4.Text =
"|"
txtPart4.SetValue(Grid.ColumnProperty, 4)
grdHeader.Children.Add(txtPart4)
Dim btnSelect As New Button
btnSelect.Width = 55
btnSelect.Cursor = Cursors.Hand
btnSelect.SetValue(Grid.ColumnProperty, 5)
grdHeader.Children.Add(btnSelect)
expanderPanel.Header = grdHeader
'Panel Content
Dim grdContent As Grid = New Grid()
Dim columnA As New ColumnDefinition
columnA.Width =
New GridLength(100)
grdContent.ColumnDefinitions.Add(columnA)
'column added
Dim columnAC As New ColumnDefinition
columnAC.Width =
New GridLength(150)
grdContent.ColumnDefinitions.Add(columnAC)
Dim columnPart1 As New ColumnDefinition
columnPart1.Width =
New GridLength(5)
grdContent.ColumnDefinitions.Add(columnPart1)
Dim columnB As New ColumnDefinition
columnB.Width =
New GridLength(150)
grdContent.ColumnDefinitions.Add(columnB)
'column added
Dim columnBC As New ColumnDefinition
columnAC.Width =
New GridLength(200)
grdContent.ColumnDefinitions.Add(columnBC)
Dim columnPart2 As New ColumnDefinition
columnPart2.Width =
New GridLength(5)
grdContent.ColumnDefinitions.Add(columnPart2)
'column added
Dim columnCA As New ColumnDefinition
columnCA.Width =
New GridLength(100)
grdContent.ColumnDefinitions.Add(columnCA)
Dim columnC As New ColumnDefinition
columnC.Width =
New GridLength(140)
grdContent.ColumnDefinitions.Add(columnC)
Dim rowA As New RowDefinition
rowA.Height =
New GridLength(5)
grdContent.RowDefinitions.Add(rowA)
'Dim rowAC As New RowDefinition
'rowAC.Height = New GridLength(5)
'grdContent.RowDefinitions.Add(rowAC)
Dim rowB As New RowDefinition
'rowB.Height = New GridLength(25)
'rowB.
grdContent.RowDefinitions.Add(rowB)
Dim rowC As New RowDefinition
'rowC.Height = New GridLength(25)
grdContent.RowDefinitions.Add(rowC)
Dim rowD As New RowDefinition
rowD.Height =
New GridLength(25)
grdContent.RowDefinitions.Add(rowD)
Dim rowE As New RowDefinition
rowE.Height =
New GridLength(10)
grdContent.RowDefinitions.Add(rowE)
Dim tbHeading1 As New TextBlock
tbHeading1.Text =
"Company Name : "
tbHeading1.TextAlignment = TextAlignment.Right
tbHeading1.SetValue(Grid.ColumnProperty, 0)
tbHeading1.SetValue(Grid.RowProperty, 1)
grdContent.Children.Add(tbHeading1)
Dim tbComName As New TextBlock
' tbComName.AcceptsReturn = True
'tbComName.IsReadOnly = True
tbComName.Text =
"CompanyName" + Convert.ToString(i)
tbComName.TextAlignment = TextAlignment.Left
tbComName.TextWrapping = TextWrapping.Wrap
tbComName.SetValue(Grid.ColumnProperty, 1)
tbComName.SetValue(Grid.RowProperty, 1)
grdContent.Children.Add(tbComName)
Dim tbContName As New TextBlock
'Dim str3 As String
Dim tbHeading As New TextBlock
tbHeading.Text =
"Contact Name : "
tbHeading.TextAlignment = TextAlignment.Right
tbHeading.SetValue(Grid.ColumnProperty, 0)
tbHeading.SetValue(Grid.RowProperty, 2)
grdContent.Children.Add(tbHeading)
tbContName.Text =
"ContactName" + Convert.ToString(i)
tbContName.TextAlignment = TextAlignment.Left
tbContName.TextWrapping = TextWrapping.Wrap
'str3 = tbComName.Text.Substring(7, 1)
'tbComName.Text.Replace(str3, " ")
tbContName.SetValue(Grid.ColumnProperty, 1)
tbContName.SetValue(Grid.RowProperty, 2)
grdContent.Children.Add(tbContName)
'str3 = tbContName.Text.Replace(tbContName.Text.Substring(7, 1), " ")
'tbContName.Text = str3
Dim txtPart5 As New TextBlock
txtPart5.Text =
"|"
txtPart5.SetValue(Grid.ColumnProperty, 2)
txtPart5.SetValue(Grid.RowProperty, 1)
grdContent.Children.Add(txtPart5)
Dim txtPart6 As New TextBlock
txtPart6.Text =
"|"
txtPart6.SetValue(Grid.ColumnProperty, 2)
txtPart6.SetValue(Grid.RowProperty, 2)
grdContent.Children.Add(txtPart6)
Dim tbHeading3 As New TextBlock
tbHeading3.Text =
"Email : "
tbHeading3.TextAlignment = TextAlignment.Right
tbHeading3.SetValue(Grid.ColumnProperty, 3)
tbHeading3.SetValue(Grid.RowProperty, 1)
grdContent.Children.Add(tbHeading3)
Dim tbHeading4 As New TextBlock
tbHeading4.Text =
"Telephone Number : "
tbHeading4.TextAlignment = TextAlignment.Right
tbHeading4.SetValue(Grid.ColumnProperty, 3)
tbHeading4.SetValue(Grid.RowProperty, 2)
grdContent.Children.Add(tbHeading4)
Dim tbEmail As New TextBlock
'Dim str3 As String
'If (obj.Email.Length > 50) Then
' str3 = obj.Email.Substring(0, 50)
' len1 = obj.Email.Length - str3.Length
' str4 = obj.Email.Substring(51, len1 - 1)
' tbEmail.TextAlignment = TextAlignment.left
' tbEmail.Text = "Email : " + str3 & Environment.NewLine + str4
'Else
tbEmail.TextAlignment = TextAlignment.Left
tbEmail.VerticalAlignment = Windows.VerticalAlignment.Stretch
tbEmail.TextWrapping = TextWrapping.Wrap
tbEmail.Text =
"Email" + Convert.ToString(i)
'End If
tbEmail.SetValue(Grid.ColumnProperty, 4)
tbEmail.SetValue(Grid.RowProperty, 1)
grdContent.Children.Add(tbEmail)
Dim txtPart7 As New TextBlock
txtPart7.Text =
"|"
txtPart7.SetValue(Grid.ColumnProperty, 5)
txtPart7.SetValue(Grid.RowProperty, 1)
grdContent.Children.Add(txtPart7)
Dim tbPhone As New TextBlock
tbPhone.Text =
"Telephone" + Convert.ToString(i)
tbPhone.TextAlignment = TextAlignment.Left
tbPhone.SetValue(Grid.ColumnProperty, 4)
tbPhone.SetValue(Grid.RowProperty, 2)
grdContent.Children.Add(tbPhone)
Dim txtPart8 As New TextBlock
txtPart8.Text =
"|"
txtPart8.SetValue(Grid.ColumnProperty, 5)
txtPart8.SetValue(Grid.RowProperty, 2)
grdContent.Children.Add(txtPart8)
Dim tbHeading5 As New TextBlock
tbHeading5.Text =
"End User Type : "
tbHeading5.TextAlignment = TextAlignment.Right
tbHeading5.SetValue(Grid.ColumnProperty, 6)
tbHeading5.SetValue(Grid.RowProperty, 1)
grdContent.Children.Add(tbHeading5)
Dim tbHeading6 As New TextBlock
tbHeading6.Text =
"City : "
tbHeading6.TextAlignment = TextAlignment.Right
tbHeading6.SetValue(Grid.ColumnProperty, 6)
tbHeading6.SetValue(Grid.RowProperty, 2)
grdContent.Children.Add(tbHeading6)
Dim tbEUType As New TextBlock
tbEUType.Text =
"EndUserType"
tbEUType.TextAlignment = TextAlignment.Left
tbEUType.TextWrapping = TextWrapping.Wrap
tbEUType.SetValue(Grid.ColumnProperty, 7)
tbEUType.SetValue(Grid.RowProperty, 1)
grdContent.Children.Add(tbEUType)
Dim tbCity As New TextBlock
tbCity.Text =
"City"
tbCity.TextAlignment = TextAlignment.Left
tbCity.TextWrapping = TextWrapping.Wrap
tbCity.SetValue(Grid.ColumnProperty, 7)
tbCity.SetValue(Grid.RowProperty, 2)
grdContent.Children.Add(tbCity)
Dim btnViewDetails As New Button
btnViewDetails.Width = 80
btnViewDetails.HorizontalAlignment = Windows.HorizontalAlignment.Left
btnViewDetails.Cursor = Cursors.Hand
btnViewDetails.SetValue(Grid.ColumnProperty, 4)
btnViewDetails.SetValue(Grid.RowProperty, 3)
grdContent.Children.Add(btnViewDetails)
expanderPanel.Content = grdContent
expanderPanel.ExpandDirection = Telerik.Windows.Controls.ExpandDirection.Down
expStack.Children.Add(expanderPanel)
Dim firstChild = TryCast(VisualTreeHelper.GetChild(expanderPanel, 0), FrameworkElement)
If Not firstChild Is Nothing Then
Dim button = TryCast(firstChild.FindName("HeaderButton"), System.Windows.Controls.Control)
button.Tag = i
End If
Next
End Sub
Private Sub expSV_LayoutUpdated(ByVal sender As System.Object, ByVal e As System.EventArgs)
Dim focusedElement As FrameworkElement = TryCast(FocusManager.GetFocusedElement(), FrameworkElement)
Dim focusedVisualTransform As GeneralTransform = focusedElement.TransformToVisual(expSV)
Dim rectangle As Rect = focusedVisualTransform.TransformBounds(New Rect(New Point(focusedElement.Margin.Left, focusedElement.Margin.Top), focusedElement.RenderSize))
Dim count As Integer = DirectCast(DirectCast(expSV.Content, System.Object), System.Windows.Controls.StackPanel).Children.Count
Dim foundElement As Boolean = False
Dim i As Integer = 1
For Each element As RadExpander In DirectCast(DirectCast(expSV.Content, System.Object), System.Windows.Controls.StackPanel).Children
Dim firstChild = TryCast(VisualTreeHelper.GetChild(element, 0), FrameworkElement)
If Not firstChild Is Nothing Then
Dim button = TryCast(firstChild.FindName("HeaderButton"), System.Windows.Controls.Control)
If foundElement Then
newOffset = firstChild
Exit For
End If
If button.Tag = focusedElement.Tag Then
foundElement =
True
If i = count Then
newOffset = firstChild
Exit For
End If
End If
End If
i = i + 1
Next
'MessageBox.Show(expStack.ActualHeight)
Dispatcher.BeginInvoke(
AddressOf UpdateScroller)
RemoveHandler expSV.LayoutUpdated, AddressOf expSV_LayoutUpdated
End Sub
End
Class
Please find attached one possible solution to your scenario.
Greetings,
Kiril Stanoev
the Telerik team