我正在寻找创建一个滚动的surfacelistbox,它会在拖动完成后自动捕捉到一个位置,以便屏幕上的中心项目在视口中居中。
我已经获得了中心项目,但现在像往常一样,WPF处理大小,屏幕位置和偏移的方式令我感到困惑。
目前我已选择订阅SurfaceScrollViewer的ManipulationCompleted事件,因为在我完成滚动手势后似乎一直闪现(而ScrollChanged事件往往会提前触发)。
void ManipCompleted(object sender, ManipulationCompletedEventArgs e)
{
FocusTaker.Focus(); //reset focus to a dummy element
List<FrameworkElement> visibleElements = new List<FrameworkElement>();
for (int i = 0; i < List.Items.Count; i++)
{
SurfaceListBoxItem item = List.ItemContainerGenerator.ContainerFromIndex(i) as SurfaceListBoxItem;
if (ViewportHelper.IsInViewport(item) && (List.Items[i] as string != "Dummy"))
{
FrameworkElement el = item as FrameworkElement;
visibleElements.Add(el);
}
}
int centerItemIdx = visibleElements.Count / 2;
FrameworkElement centerItem = visibleElements[centerItemIdx];
double center = ss.ViewportWidth / 2;
//ss is the SurfaceScrollViewer
Point itemPosition = centerItem.TransformToAncestor(ss).Transform(new Point(0, 0));
double desiredOffset = ss.HorizontalOffset + (center - itemPosition.X);
ss.ScrollToHorizontalOffset(desiredOffset);
centerItem.Focus(); //this also doesn't seem to work, but whatever.
}
列表快照,但它的快照似乎有些混乱。我在屏幕中央有一条线,有时它看起来正好位于物品的中间,但有时它会偏向一侧,甚至是物品之间。不能确定下来,但似乎列表的第一和第四个四分位数运作良好,但第二个和第三个四分位数逐渐偏向中心。
只是寻找一些如何在WPF中使用定位的帮助。所有的相对性和基于百分比的坐标和“屏幕单位”坐标之间的差异让我有点困惑。
答案 0 :(得分:2)
经过大量的反复试验后,我最终得到了这个:
void ManipCompleted(object sender, ManipulationCompletedEventArgs e)
{
FocusTaker.Focus(); //reset focus
List<FrameworkElement> visibleElements = new List<FrameworkElement>();
for (int i = 0; i < List.Items.Count; i++)
{
SurfaceListBoxItem item = List.ItemContainerGenerator.ContainerFromIndex(i) as SurfaceListBoxItem;
if (ViewportHelper.IsInViewport(item))
{
FrameworkElement el = item as FrameworkElement;
visibleElements.Add(el);
}
}
Window window = Window.GetWindow(this);
double center = ss.ViewportWidth / 2;
double closestCenterOffset = double.MaxValue;
FrameworkElement centerItem = visibleElements[0];
foreach (FrameworkElement el in visibleElements)
{
double centerOffset = Math.Abs(el.TransformToAncestor(window).Transform(new Point(0, 0)).X + (el.ActualWidth / 2) - center);
if (centerOffset < closestCenterOffset)
{
closestCenterOffset = centerOffset;
centerItem = el;
}
}
Point itemPosition = centerItem.TransformToAncestor(window).Transform(new Point(0, 0));
double desiredOffset = ss.HorizontalOffset - (center - itemPosition.X) + (centerItem.ActualWidth / 2);
ss.ScrollToHorizontalOffset(desiredOffset);
centerItem.Focus();
}
此代码块有效地确定哪个可见列表元素与列表的中心线重叠,并将该元素捕捉到精确的中心位置。捕捉有点突然,所以我将不得不考虑某种动画,但除此之外我对它很满意!我可能会使用此处的动画来制作动画:http://blogs.msdn.com/b/delay/archive/2009/08/04/scrolling-so-smooth-like-the-butter-on-a-muffin-how-to-animate-the-horizontal-verticaloffset-properties-of-a-scrollviewer.aspx
编辑:嗯,这没多久。我将ScrollViewerOffsetMediator扩展为包含HorizontalOffset,然后根据上面的帖子建议简单地创建动画。奇迹般有效。希望这最终有助于某人。
Edit2:这是SnapList的完整代码:
请注意,我很懒,因为这个项目进行了一些硬编码。需要一定的自由裁量权来确定您从此代码中执行和不需要的操作。不过,我认为这应该可以作为任何想要这种功能的人的起点。
代码也改变了我上面粘贴的内容;我发现当列表被放置在可以移动的控件中时,使用Windows.GetWindow会得到错误的结果。我做了这样你就可以为你的动作指定一个相对的控件(推荐它是层次结构中列表上方的控件)。我认为其他一些事情也发生了变化;我添加了很多自定义选项,包括能够为列表定义自定义焦点。