【问题标题】:Snapping a SurfaceListBox捕捉 SurfaceListBox
【发布时间】:2014-06-24 07:37:28
【问题描述】:

我希望创建一个滚动表面列表框,它会在拖动完成后自动捕捉到某个位置,以便屏幕上的中心项目在视口中居中。

我得到了中心项,但现在像往常一样 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 中使用定位的帮助。在这一点上,基于百分比的坐标和“屏幕单位”坐标之间的所有相关性和差异让我有些困惑。

【问题讨论】:

    标签: wpf pixelsense


    【解决方案1】:

    经过多次反复试验,我最终得到了这个:

    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 以包含 Horizo​​ntalOffset,然后按照上面帖子中的建议简单地创建了动画。奇迹般有效。希望这最终对某人有所帮助。

    Edit2:这是 SnapList 的完整代码:

    SnapList.xaml

    SnapList.xaml.cs

    请注意,由于这个项目对其中的一些内容进行了硬编码,因此我变得非常懒惰。需要一些判断力来确定您在此代码中做什么和不想要什么。尽管如此,我认为这对于任何想要此功能的人来说都应该是一个很好的起点。

    代码也与我上面粘贴的有所不同;我发现当列表位于可以移动的控件中时,使用 Windows.GetWindow 会产生不好的结果。我这样做是为了让您可以为您的运动分配一个相对于的控件(建议将其作为层次结构中列表上方的控件)。我认为其他一些事情也发生了变化。我添加了许多自定义选项,包括能够为列表定义自定义焦点。

    【讨论】:

    • 您能发布包含动画的代码吗?谢谢你。也感谢您回答您的问题。
    • 嗨 Sabuncu,我刚刚为控件添加了完整代码的 pastebin。希望你能在那里找到你需要的东西。请注意,它非常粗略,其中一些是针对我的应用程序的目的,但我希望你能得到你需要的东西。
    • +2 谢谢!将尝试并报告。
    猜你喜欢
    • 2017-07-15
    • 1970-01-01
    • 2021-07-10
    • 2012-04-27
    • 1970-01-01
    • 1970-01-01
    • 2020-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多