How do you vertically center an Expander within a ScrollViewer when it expands? [SOLVED]
-
I'm using the Silverlight 4 Tookit Expander all over the place. They are all contained within a ScrollViewer. Sometimes when I expand one of the Expander elements, the Expander.Header winds up above the top of the ScrollViewer and hence is not visible and so you can't see the title of the content that has been expanded. What I would like to do is center the Expander header vertically within the ScrollViewer viewport when I expand the Expander. To do this I have to set the ScrollViewer.VerticalOffset to the right value that will center the Expander in the ScrollViewer viewport. So I think I understand the problem that needs to be solved. But I haven't found a solution. Hopefully it's simple and I'm just overlooking something. The only ScrollViewer properties I've found that might be relevant to this problem are the following: ViewportHeight, VerticalOffset, ExtentHeight, and ActualHeight. I also have the mouse cursor Point relative to the Expander when the Expanded event takes place. But even with all this information, I don't seem to have the right information to compute what the VerticalOffset of the ScrollViewer should be. SOLUTION: Chalk up my inability to solve this to plain and simple User Brain Damage. The solution was SMOP: a Small Matter Of Programming. Most of the properties I identified above are not needed, only the following: VerticalOffset, ViewportHeight, and the Y coordinate of the mouse cursor position. Oh, yes! You have to perform the computation in the right event: Expander.SizeChanged, not Expander.Expanded. Only perform the offset if Expander.IsExpanded is true. So the code in my SizeChanged event looks like this:
private void expander_SizeChanged(object sender, SizeChangedEventArgs e)
{
Expander expander = sender as Expander;
if (expander != null && expander.IsExpanded)
{
double viewportHeight = scrollViewer.ViewportHeight;
double verticalOffset = scrollViewer.VerticalOffset;
double mouseVerticalOffset = MouseCursorPosition.Y;
double newVerticalOffset =
verticalOffset - viewportHeight / 2 + mouseVerticalOffset;
scrollViewer.ScrollToVerticalOffset(newVerticalOffset);
}
}FYI, MouseCursorPosition is one of my properties, set in my ScrollViewer's MouseMove event. Seems
-
I'm using the Silverlight 4 Tookit Expander all over the place. They are all contained within a ScrollViewer. Sometimes when I expand one of the Expander elements, the Expander.Header winds up above the top of the ScrollViewer and hence is not visible and so you can't see the title of the content that has been expanded. What I would like to do is center the Expander header vertically within the ScrollViewer viewport when I expand the Expander. To do this I have to set the ScrollViewer.VerticalOffset to the right value that will center the Expander in the ScrollViewer viewport. So I think I understand the problem that needs to be solved. But I haven't found a solution. Hopefully it's simple and I'm just overlooking something. The only ScrollViewer properties I've found that might be relevant to this problem are the following: ViewportHeight, VerticalOffset, ExtentHeight, and ActualHeight. I also have the mouse cursor Point relative to the Expander when the Expanded event takes place. But even with all this information, I don't seem to have the right information to compute what the VerticalOffset of the ScrollViewer should be. SOLUTION: Chalk up my inability to solve this to plain and simple User Brain Damage. The solution was SMOP: a Small Matter Of Programming. Most of the properties I identified above are not needed, only the following: VerticalOffset, ViewportHeight, and the Y coordinate of the mouse cursor position. Oh, yes! You have to perform the computation in the right event: Expander.SizeChanged, not Expander.Expanded. Only perform the offset if Expander.IsExpanded is true. So the code in my SizeChanged event looks like this:
private void expander_SizeChanged(object sender, SizeChangedEventArgs e)
{
Expander expander = sender as Expander;
if (expander != null && expander.IsExpanded)
{
double viewportHeight = scrollViewer.ViewportHeight;
double verticalOffset = scrollViewer.VerticalOffset;
double mouseVerticalOffset = MouseCursorPosition.Y;
double newVerticalOffset =
verticalOffset - viewportHeight / 2 + mouseVerticalOffset;
scrollViewer.ScrollToVerticalOffset(newVerticalOffset);
}
}FYI, MouseCursorPosition is one of my properties, set in my ScrollViewer's MouseMove event. Seems
fjparisIII wrote:
Only perform the offset if Expander.IsExpanded is true.
Actually I like it better if you center the Expander whether or not it is expanded. Now all I have to do is animate the centering so that it doesn't jump to the middle so violently.
-
fjparisIII wrote:
Only perform the offset if Expander.IsExpanded is true.
Actually I like it better if you center the Expander whether or not it is expanded. Now all I have to do is animate the centering so that it doesn't jump to the middle so violently.
fjparisIII wrote:
Now all I have to do is animate the centering so that it doesn't jump to the middle so violently.
Impossible, at least by using a Storyboard. The only thing you can animate with a Storyboard is a Dependency Property and the ScrollViewer's VerticalOffset property is read-only. Major bummer. Why did they do that??? Googled around a bit and I found two workarounds. First you can write a ScrollViewer extension adding a dependency property implemented using ScrollViewer.ScrollToVerticalOffset(). Second, you can bite the bullet and do it the old-fashioned way: use a DispatcherTimer, which itself would call ScrollToVerticalOffset().
-
I'm using the Silverlight 4 Tookit Expander all over the place. They are all contained within a ScrollViewer. Sometimes when I expand one of the Expander elements, the Expander.Header winds up above the top of the ScrollViewer and hence is not visible and so you can't see the title of the content that has been expanded. What I would like to do is center the Expander header vertically within the ScrollViewer viewport when I expand the Expander. To do this I have to set the ScrollViewer.VerticalOffset to the right value that will center the Expander in the ScrollViewer viewport. So I think I understand the problem that needs to be solved. But I haven't found a solution. Hopefully it's simple and I'm just overlooking something. The only ScrollViewer properties I've found that might be relevant to this problem are the following: ViewportHeight, VerticalOffset, ExtentHeight, and ActualHeight. I also have the mouse cursor Point relative to the Expander when the Expanded event takes place. But even with all this information, I don't seem to have the right information to compute what the VerticalOffset of the ScrollViewer should be. SOLUTION: Chalk up my inability to solve this to plain and simple User Brain Damage. The solution was SMOP: a Small Matter Of Programming. Most of the properties I identified above are not needed, only the following: VerticalOffset, ViewportHeight, and the Y coordinate of the mouse cursor position. Oh, yes! You have to perform the computation in the right event: Expander.SizeChanged, not Expander.Expanded. Only perform the offset if Expander.IsExpanded is true. So the code in my SizeChanged event looks like this:
private void expander_SizeChanged(object sender, SizeChangedEventArgs e)
{
Expander expander = sender as Expander;
if (expander != null && expander.IsExpanded)
{
double viewportHeight = scrollViewer.ViewportHeight;
double verticalOffset = scrollViewer.VerticalOffset;
double mouseVerticalOffset = MouseCursorPosition.Y;
double newVerticalOffset =
verticalOffset - viewportHeight / 2 + mouseVerticalOffset;
scrollViewer.ScrollToVerticalOffset(newVerticalOffset);
}
}FYI, MouseCursorPosition is one of my properties, set in my ScrollViewer's MouseMove event. Seems
-
Did you try setting the
VerticalContentAlignment
and theVerticalAlignment
tostretch
for the expander and for the scrollviewer?My signature "sucks" today
Abhinav S wrote:
Did you try setting the VerticalContentAlignment and the VerticalAlignment to stretch for the expander and for the scrollviewer?
No. What's that supposed to accomplish? The solution I posted works perfectly fine. Besides, I've moved beyond that now and am working on animating the scroll to the center of the viewport, using a
DispatcherTimer
. I've got it working beautifully, but I had to set the timer interval to 1/120 of a second to get a smooth scroll. 1/60 of a second for some reason produces a jerky scroll. I've been experimenting with the duration. So far I like a duration of 0.2 seconds, producing 24 intervals. Each interval scrolls 15 vertical pixels within a viewport of 860 pixels (i.e. scrolling a little less than 430 pixels when theExpander
is at the top of the viewport). Eminently smooth. Anyhow, this animation stuff is far more interesting than centering theExpander
, which as far as I'm concerned I solved to my satisfaction hours ago. I'll show my animation code when I've sufficiently polished it. I've created a class to perform the animation, because I have about 100Expander
elements in 12 different classes, so I need to be clean about this. -
Abhinav S wrote:
Did you try setting the VerticalContentAlignment and the VerticalAlignment to stretch for the expander and for the scrollviewer?
No. What's that supposed to accomplish? The solution I posted works perfectly fine. Besides, I've moved beyond that now and am working on animating the scroll to the center of the viewport, using a
DispatcherTimer
. I've got it working beautifully, but I had to set the timer interval to 1/120 of a second to get a smooth scroll. 1/60 of a second for some reason produces a jerky scroll. I've been experimenting with the duration. So far I like a duration of 0.2 seconds, producing 24 intervals. Each interval scrolls 15 vertical pixels within a viewport of 860 pixels (i.e. scrolling a little less than 430 pixels when theExpander
is at the top of the viewport). Eminently smooth. Anyhow, this animation stuff is far more interesting than centering theExpander
, which as far as I'm concerned I solved to my satisfaction hours ago. I'll show my animation code when I've sufficiently polished it. I've created a class to perform the animation, because I have about 100Expander
elements in 12 different classes, so I need to be clean about this.fjparisIII wrote:
VerticalContentAlignment and the VerticalAlignment to stretch
These are supposed to place a control within another control. I would suggest you have a look at the documentation (for them) on msdn. And you would need to set the properties to "center" and not "stretch" as I mentioned above. I'm glad that you have managed to get this working using a workaround though.
My signature "sucks" today
-
fjparisIII wrote:
VerticalContentAlignment and the VerticalAlignment to stretch
These are supposed to place a control within another control. I would suggest you have a look at the documentation (for them) on msdn. And you would need to set the properties to "center" and not "stretch" as I mentioned above. I'm glad that you have managed to get this working using a workaround though.
My signature "sucks" today
Abhinav S wrote:
These are supposed to...
etc. I know what they both do. I use them all the time, both in Silverlight and WPF. I just don't see their relevance to the problem I was trying to solve.
Abhinav S wrote:
I'm glad that you have managed to get this working using a workaround though.
You're talking about the centering of the
Expander
s, correct? I'd hardly call my solution a "workaround." It's a straightforward solution, direct and to the point. Maybe I didn't explain carefully enough what I'm trying to do. I have extensive product documentation on my Website. I have a product overview, ten tutorials, plus an "Easter egg" that gives background on how such a product ever came to be developed. Each document is initially presented as a list ofExpander
s within aScrollViewer
. The average list has about 8Expander
s and eachExpander
expands and collapses on average 8 lines of wrapping text per paragraph and maybe 5 or 6 paragraphs. The problem was to vertically center anExpander
header when the user clicks on it. However, doing that was just a matter of SMOP, nothing esoteric about it at all, and I shouldn't even have asked the question to begin with. But then I immediately saw that the expansion/collapse took place so fast that it was disconcerting and that it needed to be animated. That's really the interesting part of this entire discussion, and I'm still working on it to capture all the end cases. Should have it all worked out sometime this morning, and then I'll present it under Tips and Tricks. Anyhow, I don't see howVerticalContentAlignment
would play a role in this, since I don't want to keep the content vertically aligned, but only vertically aligned when the user clicks on theExpander
header, and only the header for that oneExpander
, not all of them. -
Abhinav S wrote:
These are supposed to...
etc. I know what they both do. I use them all the time, both in Silverlight and WPF. I just don't see their relevance to the problem I was trying to solve.
Abhinav S wrote:
I'm glad that you have managed to get this working using a workaround though.
You're talking about the centering of the
Expander
s, correct? I'd hardly call my solution a "workaround." It's a straightforward solution, direct and to the point. Maybe I didn't explain carefully enough what I'm trying to do. I have extensive product documentation on my Website. I have a product overview, ten tutorials, plus an "Easter egg" that gives background on how such a product ever came to be developed. Each document is initially presented as a list ofExpander
s within aScrollViewer
. The average list has about 8Expander
s and eachExpander
expands and collapses on average 8 lines of wrapping text per paragraph and maybe 5 or 6 paragraphs. The problem was to vertically center anExpander
header when the user clicks on it. However, doing that was just a matter of SMOP, nothing esoteric about it at all, and I shouldn't even have asked the question to begin with. But then I immediately saw that the expansion/collapse took place so fast that it was disconcerting and that it needed to be animated. That's really the interesting part of this entire discussion, and I'm still working on it to capture all the end cases. Should have it all worked out sometime this morning, and then I'll present it under Tips and Tricks. Anyhow, I don't see howVerticalContentAlignment
would play a role in this, since I don't want to keep the content vertically aligned, but only vertically aligned when the user clicks on theExpander
header, and only the header for that oneExpander
, not all of them.fjparisIII wrote:
Should have it all worked out sometime this morning, and then I'll present it under Tips and Tricks.
Here is the link: http://www.codeproject.com/Tips/85359/How-to-animate-vertical-centering-of-a-Silverlight.aspx[^]