我的应用包含ScrollViewer
和StackPanel
。
XAML:
<Window x:Class="WpfScrollViewer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="500" Width="800" Loaded="MainWindow_OnLoaded">
<Window.Resources>
<Style TargetType="Rectangle">
<Setter Property="Fill" Value="Blue" />
<Setter Property="Margin" Value="10" />
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="50" />
</Grid.RowDefinitions>
<ScrollViewer x:Name="MyScrollViewer" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Auto">
<StackPanel x:Name="MyStackPanel" Orientation="Horizontal" />
</ScrollViewer>
<Button Grid.Row="1" Width="50" HorizontalAlignment="Left" Content="left" Click="LeftButton_Click" />
<Button Grid.Row="1" Width="50" HorizontalAlignment="Right" Content="right" Click="RightButton_Click" />
</Grid>
</Window>
在StackPanel
内部我从后面的代码中创建了几个Rectangle
,其宽度是根据我的Window
的宽度计算出来的。
背后的代码:
using System.Windows;
using System.Windows.Shapes;
namespace WpfScrollViewer
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private double _scrollWidth;
private double _edgeScrollWidth;
public MainWindow()
{
InitializeComponent();
}
private void LeftButton_Click(object sender, RoutedEventArgs e)
{
var offset = MyScrollViewer.HorizontalOffset;
if (offset == MyScrollViewer.ScrollableWidth)
{
MyScrollViewer.ScrollToHorizontalOffset(offset - _edgeScrollWidth);
}
else
{
MyScrollViewer.ScrollToHorizontalOffset(offset - _scrollWidth);
}
}
private void RightButton_Click(object sender, RoutedEventArgs e)
{
var offset = MyScrollViewer.HorizontalOffset;
if (offset == 0)
{
MyScrollViewer.ScrollToHorizontalOffset(offset + _edgeScrollWidth);
}
else
{
MyScrollViewer.ScrollToHorizontalOffset(offset + _scrollWidth);
}
}
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
_scrollWidth = Width - 60;
_edgeScrollWidth = Width - 90;
var itemWidth = Width - 80;
for (var i = 0; i < 10; i++)
{
MyStackPanel.Children.Add(new Rectangle { Width = itemWidth });
}
}
}
}
当我按右Button
时,我的矩形看起来像这样:
但我想看到两侧矩形的相等部分。我想让我的整个矩形居中,而不是。我真的认为我正确计算了偏移量,所以我真的不知道我错在哪里
我是否遗漏了某些内容,或者使用
WPF
独立单位进行计算时遇到了一些问题?
答案 0 :(得分:1)
我的问题源于我在Width
事件处理程序中使用Loaded
属性。 Width
这里是Window
类的width属性,该属性的值包含窗口边框的宽度。您真正想要的是窗口内部部分的宽度,或客户区。没有WPF属性,因此您需要使用窗口的子元素ActualWidth
(窗口Content
)。
另外,我建议摆脱&#34;魔法&#34;数字通过将它们转换为常数。
以下是您的代码的重新编译版本,可以执行您想要的操作:
const double RectangleMarginThickness = 10;
const double RectangleWidthReduction = 80; // Rect width is client width less this
const double PaddingToCenter = RectangleWidthReduction/2 - RectangleMarginThickness;
double _rectangleWidthIncludingMargin;
private void MainWindow_OnLoaded(object sender, RoutedEventArgs e)
{
double clientWidth = (Content as FrameworkElement).ActualWidth;
var itemWidth = clientWidth - RectangleWidthReduction;
_rectangleWidthIncludingMargin = itemWidth + (RectangleMarginThickness * 2);
for (var i = 0; i < 10; i++)
{
MyStackPanel.Children.Add(new Rectangle { Width = itemWidth });
}
}
private void LeftButton_Click(object sender, RoutedEventArgs e)
{
SetNewHorizontalOffset(childOffset: -1);
}
private void RightButton_Click(object sender, RoutedEventArgs e)
{
SetNewHorizontalOffset(childOffset: 1);
}
private void SetNewHorizontalOffset(int childOffset)
{
double offset = MyScrollViewer.HorizontalOffset + PaddingToCenter;
if (_rectangleWidthIncludingMargin > 0)
{
int currentChildIndex;
if (childOffset < 0)
{
currentChildIndex =
(int) Math.Ceiling(offset / _rectangleWidthIncludingMargin);
}
else
{
currentChildIndex =
(int) Math.Floor(offset / _rectangleWidthIncludingMargin);
}
int newChildIndex = CoerceToRange(currentChildIndex + childOffset,
0, MyStackPanel.Children.Count - 1);
offset = newChildIndex * _rectangleWidthIncludingMargin - PaddingToCenter;
}
MyScrollViewer.ScrollToHorizontalOffset(offset);
}
private static int CoerceToRange(int value, int minimum, int maximum)
{
return Math.Max(minimum, Math.Min(value, maximum));
}