计算 ScrollViewer 的滚动条偏移量,使对象居中,同时保持比例可变的布局变换
Calculate a ScrollViewer's scrollbar offsets so that an object will be centered, while maintaining a layout transform who's scale is variable
我已经和这个问题争论了好几个小时了,我似乎无法得出一个可以接受的答案。我希望那里的几何技能比我自己强得多的人可以为我解决这个谜语。任何帮助将不胜感激。我的问题的性质和描述在我提供的图片下方。
这里是我构建的示例项目,它没有正确满足要求。
XAML:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Center and Zoom ScrollViewer Test" Height="600" Width="800" WindowStartupLocation="CenterScreen">
<Grid>
<DockPanel>
<GroupBox Header="Parameters" DockPanel.Dock="Top" Margin="10">
<StackPanel Orientation="Horizontal">
<GroupBox Header="Manually Set ScrollBar Positions" Margin="10">
<StackPanel Orientation="Horizontal">
<TextBox Name="EditHorz" Width="60" Margin="10" TextChanged="EditHorz_TextChanged" />
<Label Content="x" Margin="0 10 0 10" />
<TextBox Name="EditVert" Width="60" Margin="10" TextChanged="EditVert_TextChanged" />
</StackPanel>
</GroupBox>
<GroupBox Header="Scale" Margin="10">
<DockPanel>
<Label Content="{Binding ElementName=scaleValue, Path=Value}" DockPanel.Dock="Right" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Width="40" />
<Slider Name="scaleValue" Minimum="1" Maximum="4" SmallChange="0.05" LargeChange="0.1" Width="200" VerticalAlignment="Center" />
</DockPanel>
</GroupBox>
</StackPanel>
</GroupBox>
<GroupBox Header="Debug Output" Margin="10">
<TextBox Name="text" FontFamily="Courier New" FontSize="12" DockPanel.Dock="Left" Width="500" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" Margin="10" />
</GroupBox>
<GroupBox Header="Proof" Margin="10">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Button Width="60" HorizontalAlignment="Left" Content="Center" Click="ButtonCenter_Click" Margin="10" />
<Button Width="60" HorizontalAlignment="Left" Content="Reset" Click="ButtonReset_Click" Margin="10" />
</StackPanel>
<ScrollViewer Name="scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" Background="Green" Width="100" Height="100" VerticalAlignment="Top" Margin="10">
<Canvas Width="200" Height="200" Background="Red">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=scaleValue, Path=Value}" ScaleY="{Binding ElementName=scaleValue, Path=Value}" />
</Canvas.LayoutTransform>
<Rectangle Name="rect" Width="40" Height="40" Canvas.Left="120" Canvas.Top="70" Fill="Blue" />
</Canvas>
</ScrollViewer>
</DockPanel>
</GroupBox>
</DockPanel>
</Grid>
代码隐藏 (VB.net)
Class MainWindow
''' Calculates the horizontal and vertical scrollbar offsets so that
''' the blue rectangle is centered within the scroll viewer.
Private Sub RecalculateCenter()
' the scale we are using
Dim scale As Double = scaleValue.Value
' get the rectangles current position within the canvas
Dim rectLeft As Double = Canvas.GetLeft(rect)
Dim rectTop As Double = Canvas.GetTop(rect)
' set our point of interest "Rect" equal to the the whole coordinates of the rectangle
Dim poi As Rect = New Rect(rectLeft, rectTop, rect.Width, rect.Height)
' get our view offset
Dim ofsViewWidth As Double = (scroll.ScrollableWidth - (((scroll.ViewportWidth / 2) - (rect.ActualWidth / 2)) * scale)) / scale
Dim ofsViewHeight As Double = (scroll.ScrollableHeight - (((scroll.ViewportHeight / 2) - (rect.ActualHeight / 2)) * scale)) / scale
' calculate our scroll bar offsets
Dim verticalOffset As Double = (poi.Top - ofsViewHeight) * scale
Dim horizontalOffset As Double = (poi.Left - ofsViewWidth) * scale
' record the output to the debug output window
Dim sb As New StringBuilder()
sb.AppendLine($"Scale : {scale}")
sb.AppendLine($"POI : {poi.ToString()}")
sb.AppendLine($"Rect : {rectLeft}x{rectTop}")
sb.AppendLine($"Extent : {scroll.ExtentWidth}x{scroll.ExtentHeight}")
sb.AppendLine($"Scrollable : {scroll.ScrollableWidth}x{scroll.ScrollableHeight}")
sb.AppendLine($"View Offset: {ofsViewWidth}x{ofsViewHeight}")
sb.AppendLine($"Horizontal : {horizontalOffset}")
sb.AppendLine($"Vertical : {verticalOffset}")
text.Text = sb.ToString()
' set the EditHorz and EditVert text box values, this will trigger the scroll
' bar offsets to fire via the TextChanged event handlers
EditHorz.Text = horizontalOffset.ToString()
EditVert.Text = verticalOffset.ToString()
End Sub
''' Try and parse the horizontal text box to a double, and set the scroll bar position accordingly
Private Sub SetScrollBarHorizontalOffset()
Dim ofs As Double = 0
If Double.TryParse(EditHorz.Text, ofs) Then
scroll.ScrollToHorizontalOffset(ofs)
End If
End Sub
''' Try and parse the vertical text box to a double, and set the scroll bar position accordingly
Private Sub SetScrollBarVerticalOffset()
Dim ofs As Double = 0
ofs = 0
If Double.TryParse(EditVert.Text, ofs) Then
scroll.ScrollToVerticalOffset(ofs)
End If
End Sub
''' Parse and set scrollbars positions for both Horizontal and Vertical
Private Sub SetScrollBarOffsets()
SetScrollBarHorizontalOffset()
SetScrollBarVerticalOffset()
End Sub
Private Sub ButtonCenter_Click(sender As Object, e As RoutedEventArgs)
RecalculateCenter()
End Sub
Private Sub ButtonReset_Click(sender As Object, e As RoutedEventArgs)
scroll.ScrollToVerticalOffset(0)
scroll.ScrollToHorizontalOffset(0)
End Sub
Private Sub EditHorz_TextChanged(sender As Object, e As TextChangedEventArgs)
SetScrollBarOffsets()
End Sub
Private Sub EditVert_TextChanged(sender As Object, e As TextChangedEventArgs)
SetScrollBarOffsets()
End Sub
结束Class
经过多次试验和错误,并将其逐个分解,我终于能够使这段代码正常工作。我希望其他人会发现这很有用。解决方法如下:
XAML:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Center and Zoom ScrollViewer Test" Height="600" Width="800" WindowStartupLocation="CenterScreen">
<Grid>
<DockPanel>
<GroupBox Header="Parameters" DockPanel.Dock="Top" Margin="10">
<StackPanel Orientation="Horizontal">
<GroupBox Header="Manually Set ScrollBar Positions" Margin="10">
<StackPanel Orientation="Horizontal">
<TextBox Name="EditHorz" Width="60" Margin="10" TextChanged="EditHorz_TextChanged" />
<Label Content="x" Margin="0 10 0 10" />
<TextBox Name="EditVert" Width="60" Margin="10" TextChanged="EditVert_TextChanged" />
</StackPanel>
</GroupBox>
<GroupBox Header="Scale" Margin="10">
<DockPanel>
<Label Content="{Binding ElementName=scaleValue, Path=Value, StringFormat={}{0:F2}}" DockPanel.Dock="Right" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Width="40" />
<Slider Name="scaleValue" Minimum="1" Maximum="4" SmallChange="0.05" LargeChange="0.1" Width="200" VerticalAlignment="Center" />
</DockPanel>
</GroupBox>
</StackPanel>
</GroupBox>
<GroupBox Header="Debug Output" Margin="10">
<TextBox Name="text" FontFamily="Courier New" FontSize="12" DockPanel.Dock="Left" Width="500" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" Margin="10" />
</GroupBox>
<GroupBox Header="Proof" Margin="10">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Button Width="60" HorizontalAlignment="Left" Content="Center" Click="ButtonCenter_Click" Margin="10" />
<Button Width="60" HorizontalAlignment="Left" Content="Reset" Click="ButtonReset_Click" Margin="10" />
</StackPanel>
<ScrollViewer Name="scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" Background="Green" Width="100" Height="100" VerticalAlignment="Top" Margin="10">
<Canvas Width="200" Height="200" Background="Red">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=scaleValue, Path=Value}" ScaleY="{Binding ElementName=scaleValue, Path=Value}" />
</Canvas.LayoutTransform>
<Rectangle Name="rect" Width="40" Height="40" Canvas.Left="120" Canvas.Top="70" Fill="Blue" />
</Canvas>
</ScrollViewer>
</DockPanel>
</GroupBox>
</DockPanel>
</Grid>
代码隐藏 (VB.net):
Class MainWindow
' Calculates the horizontal and vertical scrollbar offsets so that
' the blue rectangle is centered within the scroll viewer.
Private Sub RecalculateCenter()
' the scale we are using
Dim scale As Double = scaleValue.Value
' get our rectangles left and top properties
Dim rectLeft As Double = Canvas.GetLeft(rect) * scale
Dim rectTop As Double = Canvas.GetTop(rect) * scale
Dim rectWidth As Double = rect.Width * scale
Dim rectHeight As Double = rect.Height * scale
' set our point of interest "Rect" equal to the the whole coordinates of the rectangle
Dim poi As Rect = New Rect(rectLeft, rectTop, rectWidth, rectHeight)
' get top and left center values
Dim horizontalCenter As Double = ((scroll.ViewportWidth / 2) - (rectWidth / 2))
Dim verticalCenter As Double = ((scroll.ViewportHeight / 2) - (rectHeight / 2))
' get our center of viewport with relation to the poi
Dim viewportCenter As New Rect(horizontalCenter, verticalCenter, rectWidth, rectHeight)
' calculate our scroll bar offsets
Dim verticalOffset As Double = (poi.Top) - (viewportCenter.Top)
Dim horizontalOffset As Double = (poi.Left) - (viewportCenter.Left)
' record the output to the debug output window
Dim sb As New StringBuilder()
sb.AppendLine($"Scale .............. {scale,0:F2}")
sb.AppendLine($"rectLeft ........... {rectLeft,0:F0}")
sb.AppendLine($"rectTop ............ {rectTop,0:F0}")
sb.AppendLine($"POI ................ {poi.Left,0:F0},{poi.Top,0:F0},{poi.Width,0:F0},{poi.Height,0:F0}")
sb.AppendLine($"Horz Center ........ {horizontalCenter,0:F0}")
sb.AppendLine($"Vert Center ........ {verticalCenter,0:F0}")
sb.AppendLine($"View Center ........ {viewportCenter.Left,0:F0},{viewportCenter.Top,0:F0},{viewportCenter.Width,0:F0},{viewportCenter.Height,0:F0}")
sb.AppendLine($"Horizontal ......... {horizontalOffset,0:F0}")
sb.AppendLine($"Vertical ........... {verticalOffset,0:F0}")
sb.AppendLine($"------------------------------------")
sb.AppendLine($"ViewPort ........... {scroll.ViewportWidth,0:F0} x {scroll.ViewportHeight,0:F0}")
sb.AppendLine($"Extent ............. {scroll.ExtentWidth,0:F0} x {scroll.ExtentHeight,0:F0}")
sb.AppendLine($"Scrollable ......... {scroll.ScrollableWidth,0:F0} x {scroll.ScrollableHeight,0:F0}")
text.Text = sb.ToString()
' set the EditHorz and EditVert text box values, this will trigger the scroll
' bar offsets to fire via the TextChanged event handlers
EditHorz.Text = $"{horizontalOffset,0:F2}"
EditVert.Text = $"{verticalOffset,0:F2}"
End Sub
' Try and parse the horizontal text box to a double, and set the scroll bar position accordingly
Private Sub SetScrollBarHorizontalOffset()
Dim ofs As Double = 0
If Double.TryParse(EditHorz.Text, ofs) Then
scroll.ScrollToHorizontalOffset(ofs)
Else
scroll.ScrollToHome()
End If
End Sub
' Try and parse the vertical text box to a double, and set the scroll bar position accordingly
Private Sub SetScrollBarVerticalOffset()
Dim ofs As Double = 0
ofs = 0
If Double.TryParse(EditVert.Text, ofs) Then
scroll.ScrollToVerticalOffset(ofs)
Else
scroll.ScrollToHome()
End If
End Sub
' Parse and set scrollbars positions for both Horizontal and Vertical
Private Sub SetScrollBarOffsets()
SetScrollBarHorizontalOffset()
SetScrollBarVerticalOffset()
End Sub
Private Sub ButtonCenter_Click(sender As Object, e As RoutedEventArgs)
RecalculateCenter()
End Sub
Private Sub ButtonReset_Click(sender As Object, e As RoutedEventArgs)
EditHorz.Text = String.Empty
EditVert.Text = String.Empty
End Sub
Private Sub EditHorz_TextChanged(sender As Object, e As TextChangedEventArgs)
SetScrollBarOffsets()
End Sub
Private Sub EditVert_TextChanged(sender As Object, e As TextChangedEventArgs)
SetScrollBarOffsets()
End Sub
Private Sub scaleValue_ValueChanged(sender As Object, e As RoutedPropertyChangedEventArgs(Of Double)) Handles scaleValue.ValueChanged
Dispatcher.BeginInvoke(Sub() RecalculateCenter())
End Sub
结束Class
我已经和这个问题争论了好几个小时了,我似乎无法得出一个可以接受的答案。我希望那里的几何技能比我自己强得多的人可以为我解决这个谜语。任何帮助将不胜感激。我的问题的性质和描述在我提供的图片下方。
这里是我构建的示例项目,它没有正确满足要求。
XAML:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Center and Zoom ScrollViewer Test" Height="600" Width="800" WindowStartupLocation="CenterScreen">
<Grid>
<DockPanel>
<GroupBox Header="Parameters" DockPanel.Dock="Top" Margin="10">
<StackPanel Orientation="Horizontal">
<GroupBox Header="Manually Set ScrollBar Positions" Margin="10">
<StackPanel Orientation="Horizontal">
<TextBox Name="EditHorz" Width="60" Margin="10" TextChanged="EditHorz_TextChanged" />
<Label Content="x" Margin="0 10 0 10" />
<TextBox Name="EditVert" Width="60" Margin="10" TextChanged="EditVert_TextChanged" />
</StackPanel>
</GroupBox>
<GroupBox Header="Scale" Margin="10">
<DockPanel>
<Label Content="{Binding ElementName=scaleValue, Path=Value}" DockPanel.Dock="Right" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Width="40" />
<Slider Name="scaleValue" Minimum="1" Maximum="4" SmallChange="0.05" LargeChange="0.1" Width="200" VerticalAlignment="Center" />
</DockPanel>
</GroupBox>
</StackPanel>
</GroupBox>
<GroupBox Header="Debug Output" Margin="10">
<TextBox Name="text" FontFamily="Courier New" FontSize="12" DockPanel.Dock="Left" Width="500" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" Margin="10" />
</GroupBox>
<GroupBox Header="Proof" Margin="10">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Button Width="60" HorizontalAlignment="Left" Content="Center" Click="ButtonCenter_Click" Margin="10" />
<Button Width="60" HorizontalAlignment="Left" Content="Reset" Click="ButtonReset_Click" Margin="10" />
</StackPanel>
<ScrollViewer Name="scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" Background="Green" Width="100" Height="100" VerticalAlignment="Top" Margin="10">
<Canvas Width="200" Height="200" Background="Red">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=scaleValue, Path=Value}" ScaleY="{Binding ElementName=scaleValue, Path=Value}" />
</Canvas.LayoutTransform>
<Rectangle Name="rect" Width="40" Height="40" Canvas.Left="120" Canvas.Top="70" Fill="Blue" />
</Canvas>
</ScrollViewer>
</DockPanel>
</GroupBox>
</DockPanel>
</Grid>
代码隐藏 (VB.net)
Class MainWindow
''' Calculates the horizontal and vertical scrollbar offsets so that
''' the blue rectangle is centered within the scroll viewer.
Private Sub RecalculateCenter()
' the scale we are using
Dim scale As Double = scaleValue.Value
' get the rectangles current position within the canvas
Dim rectLeft As Double = Canvas.GetLeft(rect)
Dim rectTop As Double = Canvas.GetTop(rect)
' set our point of interest "Rect" equal to the the whole coordinates of the rectangle
Dim poi As Rect = New Rect(rectLeft, rectTop, rect.Width, rect.Height)
' get our view offset
Dim ofsViewWidth As Double = (scroll.ScrollableWidth - (((scroll.ViewportWidth / 2) - (rect.ActualWidth / 2)) * scale)) / scale
Dim ofsViewHeight As Double = (scroll.ScrollableHeight - (((scroll.ViewportHeight / 2) - (rect.ActualHeight / 2)) * scale)) / scale
' calculate our scroll bar offsets
Dim verticalOffset As Double = (poi.Top - ofsViewHeight) * scale
Dim horizontalOffset As Double = (poi.Left - ofsViewWidth) * scale
' record the output to the debug output window
Dim sb As New StringBuilder()
sb.AppendLine($"Scale : {scale}")
sb.AppendLine($"POI : {poi.ToString()}")
sb.AppendLine($"Rect : {rectLeft}x{rectTop}")
sb.AppendLine($"Extent : {scroll.ExtentWidth}x{scroll.ExtentHeight}")
sb.AppendLine($"Scrollable : {scroll.ScrollableWidth}x{scroll.ScrollableHeight}")
sb.AppendLine($"View Offset: {ofsViewWidth}x{ofsViewHeight}")
sb.AppendLine($"Horizontal : {horizontalOffset}")
sb.AppendLine($"Vertical : {verticalOffset}")
text.Text = sb.ToString()
' set the EditHorz and EditVert text box values, this will trigger the scroll
' bar offsets to fire via the TextChanged event handlers
EditHorz.Text = horizontalOffset.ToString()
EditVert.Text = verticalOffset.ToString()
End Sub
''' Try and parse the horizontal text box to a double, and set the scroll bar position accordingly
Private Sub SetScrollBarHorizontalOffset()
Dim ofs As Double = 0
If Double.TryParse(EditHorz.Text, ofs) Then
scroll.ScrollToHorizontalOffset(ofs)
End If
End Sub
''' Try and parse the vertical text box to a double, and set the scroll bar position accordingly
Private Sub SetScrollBarVerticalOffset()
Dim ofs As Double = 0
ofs = 0
If Double.TryParse(EditVert.Text, ofs) Then
scroll.ScrollToVerticalOffset(ofs)
End If
End Sub
''' Parse and set scrollbars positions for both Horizontal and Vertical
Private Sub SetScrollBarOffsets()
SetScrollBarHorizontalOffset()
SetScrollBarVerticalOffset()
End Sub
Private Sub ButtonCenter_Click(sender As Object, e As RoutedEventArgs)
RecalculateCenter()
End Sub
Private Sub ButtonReset_Click(sender As Object, e As RoutedEventArgs)
scroll.ScrollToVerticalOffset(0)
scroll.ScrollToHorizontalOffset(0)
End Sub
Private Sub EditHorz_TextChanged(sender As Object, e As TextChangedEventArgs)
SetScrollBarOffsets()
End Sub
Private Sub EditVert_TextChanged(sender As Object, e As TextChangedEventArgs)
SetScrollBarOffsets()
End Sub
结束Class
经过多次试验和错误,并将其逐个分解,我终于能够使这段代码正常工作。我希望其他人会发现这很有用。解决方法如下:
XAML:
<Window x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="Center and Zoom ScrollViewer Test" Height="600" Width="800" WindowStartupLocation="CenterScreen">
<Grid>
<DockPanel>
<GroupBox Header="Parameters" DockPanel.Dock="Top" Margin="10">
<StackPanel Orientation="Horizontal">
<GroupBox Header="Manually Set ScrollBar Positions" Margin="10">
<StackPanel Orientation="Horizontal">
<TextBox Name="EditHorz" Width="60" Margin="10" TextChanged="EditHorz_TextChanged" />
<Label Content="x" Margin="0 10 0 10" />
<TextBox Name="EditVert" Width="60" Margin="10" TextChanged="EditVert_TextChanged" />
</StackPanel>
</GroupBox>
<GroupBox Header="Scale" Margin="10">
<DockPanel>
<Label Content="{Binding ElementName=scaleValue, Path=Value, StringFormat={}{0:F2}}" DockPanel.Dock="Right" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" Width="40" />
<Slider Name="scaleValue" Minimum="1" Maximum="4" SmallChange="0.05" LargeChange="0.1" Width="200" VerticalAlignment="Center" />
</DockPanel>
</GroupBox>
</StackPanel>
</GroupBox>
<GroupBox Header="Debug Output" Margin="10">
<TextBox Name="text" FontFamily="Courier New" FontSize="12" DockPanel.Dock="Left" Width="500" TextWrapping="Wrap" AcceptsReturn="True" AcceptsTab="True" Margin="10" />
</GroupBox>
<GroupBox Header="Proof" Margin="10">
<DockPanel>
<StackPanel Orientation="Horizontal" DockPanel.Dock="Bottom" HorizontalAlignment="Center">
<Button Width="60" HorizontalAlignment="Left" Content="Center" Click="ButtonCenter_Click" Margin="10" />
<Button Width="60" HorizontalAlignment="Left" Content="Reset" Click="ButtonReset_Click" Margin="10" />
</StackPanel>
<ScrollViewer Name="scroll" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" Background="Green" Width="100" Height="100" VerticalAlignment="Top" Margin="10">
<Canvas Width="200" Height="200" Background="Red">
<Canvas.LayoutTransform>
<ScaleTransform ScaleX="{Binding ElementName=scaleValue, Path=Value}" ScaleY="{Binding ElementName=scaleValue, Path=Value}" />
</Canvas.LayoutTransform>
<Rectangle Name="rect" Width="40" Height="40" Canvas.Left="120" Canvas.Top="70" Fill="Blue" />
</Canvas>
</ScrollViewer>
</DockPanel>
</GroupBox>
</DockPanel>
</Grid>
代码隐藏 (VB.net):
Class MainWindow
' Calculates the horizontal and vertical scrollbar offsets so that
' the blue rectangle is centered within the scroll viewer.
Private Sub RecalculateCenter()
' the scale we are using
Dim scale As Double = scaleValue.Value
' get our rectangles left and top properties
Dim rectLeft As Double = Canvas.GetLeft(rect) * scale
Dim rectTop As Double = Canvas.GetTop(rect) * scale
Dim rectWidth As Double = rect.Width * scale
Dim rectHeight As Double = rect.Height * scale
' set our point of interest "Rect" equal to the the whole coordinates of the rectangle
Dim poi As Rect = New Rect(rectLeft, rectTop, rectWidth, rectHeight)
' get top and left center values
Dim horizontalCenter As Double = ((scroll.ViewportWidth / 2) - (rectWidth / 2))
Dim verticalCenter As Double = ((scroll.ViewportHeight / 2) - (rectHeight / 2))
' get our center of viewport with relation to the poi
Dim viewportCenter As New Rect(horizontalCenter, verticalCenter, rectWidth, rectHeight)
' calculate our scroll bar offsets
Dim verticalOffset As Double = (poi.Top) - (viewportCenter.Top)
Dim horizontalOffset As Double = (poi.Left) - (viewportCenter.Left)
' record the output to the debug output window
Dim sb As New StringBuilder()
sb.AppendLine($"Scale .............. {scale,0:F2}")
sb.AppendLine($"rectLeft ........... {rectLeft,0:F0}")
sb.AppendLine($"rectTop ............ {rectTop,0:F0}")
sb.AppendLine($"POI ................ {poi.Left,0:F0},{poi.Top,0:F0},{poi.Width,0:F0},{poi.Height,0:F0}")
sb.AppendLine($"Horz Center ........ {horizontalCenter,0:F0}")
sb.AppendLine($"Vert Center ........ {verticalCenter,0:F0}")
sb.AppendLine($"View Center ........ {viewportCenter.Left,0:F0},{viewportCenter.Top,0:F0},{viewportCenter.Width,0:F0},{viewportCenter.Height,0:F0}")
sb.AppendLine($"Horizontal ......... {horizontalOffset,0:F0}")
sb.AppendLine($"Vertical ........... {verticalOffset,0:F0}")
sb.AppendLine($"------------------------------------")
sb.AppendLine($"ViewPort ........... {scroll.ViewportWidth,0:F0} x {scroll.ViewportHeight,0:F0}")
sb.AppendLine($"Extent ............. {scroll.ExtentWidth,0:F0} x {scroll.ExtentHeight,0:F0}")
sb.AppendLine($"Scrollable ......... {scroll.ScrollableWidth,0:F0} x {scroll.ScrollableHeight,0:F0}")
text.Text = sb.ToString()
' set the EditHorz and EditVert text box values, this will trigger the scroll
' bar offsets to fire via the TextChanged event handlers
EditHorz.Text = $"{horizontalOffset,0:F2}"
EditVert.Text = $"{verticalOffset,0:F2}"
End Sub
' Try and parse the horizontal text box to a double, and set the scroll bar position accordingly
Private Sub SetScrollBarHorizontalOffset()
Dim ofs As Double = 0
If Double.TryParse(EditHorz.Text, ofs) Then
scroll.ScrollToHorizontalOffset(ofs)
Else
scroll.ScrollToHome()
End If
End Sub
' Try and parse the vertical text box to a double, and set the scroll bar position accordingly
Private Sub SetScrollBarVerticalOffset()
Dim ofs As Double = 0
ofs = 0
If Double.TryParse(EditVert.Text, ofs) Then
scroll.ScrollToVerticalOffset(ofs)
Else
scroll.ScrollToHome()
End If
End Sub
' Parse and set scrollbars positions for both Horizontal and Vertical
Private Sub SetScrollBarOffsets()
SetScrollBarHorizontalOffset()
SetScrollBarVerticalOffset()
End Sub
Private Sub ButtonCenter_Click(sender As Object, e As RoutedEventArgs)
RecalculateCenter()
End Sub
Private Sub ButtonReset_Click(sender As Object, e As RoutedEventArgs)
EditHorz.Text = String.Empty
EditVert.Text = String.Empty
End Sub
Private Sub EditHorz_TextChanged(sender As Object, e As TextChangedEventArgs)
SetScrollBarOffsets()
End Sub
Private Sub EditVert_TextChanged(sender As Object, e As TextChangedEventArgs)
SetScrollBarOffsets()
End Sub
Private Sub scaleValue_ValueChanged(sender As Object, e As RoutedPropertyChangedEventArgs(Of Double)) Handles scaleValue.ValueChanged
Dispatcher.BeginInvoke(Sub() RecalculateCenter())
End Sub
结束Class