【问题标题】:Scrolling while dragging and dropping (WPF)拖放时滚动(WPF)
【发布时间】:2019-05-03 23:12:53
【问题描述】:

好的,伙计们,我一直在为这个问题抓狂,并且花了好几个小时试图研究它是如何工作的,但我还没有找到答案,如果你希望看到我的任何 SRC 随意问一下,我会看看我是否可以提供帮助。

基本上我遇到的问题是我的应用程序中有一个TreeView 文件夹,即:

Catalog

  Brands
    Nike
    Adidas
    Lactose

  Styles
    Sandles
    Trainers
    Boots

我要解决的问题是,当我拖动文件夹时(这在我的DragDropManager 类中处理),我无法向上或向下滚动(仅显示一个可爱的停止标志)。我实际上也无法在树视图中找到滚动条,所以我不确定它是如何生成的(这不是我自己的软件,我最近开始为一家公司工作,所以我不熟悉代码,也没有其他人好像知道了。)

如果我想将某些东西从最顶端移到最底端,这将是一个问题。

滚动无需拖动即可自行正常工作。

如果有人希望看到我的代码的任何部分,请随时询问,因为我不确定要向你们展示什么。

我已经阅读了好几篇文章,只是摸不着头脑。

【问题讨论】:

    标签: c# wpf drag-and-drop treeview scroll


    【解决方案1】:

    我已经创建了一个附加属性来实现这个行为,看看我的帖子在这里 -

    Attached Behavior for auto scrolling containers while doing Drag & Drop

    主要逻辑是这样的-

    private static void OnContainerPreviewDragOver(object sender, DragEventArgs e)
    {
        FrameworkElement container = sender as FrameworkElement;
    
        if (container == null) { return; }
    
        ScrollViewer scrollViewer = GetFirstVisualChild<ScrollViewer>(container);
    
        if (scrollViewer == null) { return; }
    
        double tolerance = 60;
        double verticalPos = e.GetPosition(container).Y;
        double offset = 20;
    
        if (verticalPos < tolerance) // Top of visible list? 
        {
            //Scroll up
            scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - offset);
        }
        else if (verticalPos > container.ActualHeight - tolerance) //Bottom of visible list? 
        {
            //Scroll down
            scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset + offset);     
        }
    }
    

    关于 SO 的类似问题(虽然它们主要针对 ListBox/ListView,但也适用于 TreeView)-

    WPF Listbox auto scroll while dragging

    WPF ListView Databound Drag/Drop Auto Scroll

    WPF Drag-to-scroll doesn't work correctly

    【讨论】:

    • 我一直在尝试在我的列表框上使用它,但如果列表框中的项目无法拖放,它就不起作用。我在列表框中混合了项目,有些可以放下,有些不能。如果靠近顶部(或底部)的那些无法接收掉落,则不会激活滚动。有什么想法可以解决这个问题吗?
    • @Lutz 这很有趣,从来没有遇到过这样的场景,所以不能多说。我可以想到 1. 在当前项目之间添加一些虚拟项目(高度小等,因此它们看起来不会奇怪或浪费空间),使它们可放置,以便始终调用 PreviewDragOver。但是您将不得不处理丢弃等。 2. 使所有项目可丢弃并在丢弃后处理验证。 3. 尝试查找是否为这些不可放置的项目触发了其他事件。
    • @nikotromus 你能详细说明什么不起作用吗?还有你的场景等等!
    • @akjoshi - 我已经完全按照您的指定添加了您的代码。但是,当我将行 'WpfExtensions:DragDropExtension.ScrollOnDragDrop="True"' 添加到我的 ListView 时,它给了我以下智能错误:“名称 DragDropExtension 不存在于命名空间 'clr-namespace:WpfExtensions' ”跨度>
    • 这个扩展也适用于 ScrollViewers。但是您必须将 ScrollViewer 包装在 Border 中,并将扩展名添加到边框而不是 ScrollViewer。
    【解决方案2】:

    我知道这个问题真的很老了,但这里是作为附加属性的 MVVM 方式:

        using System.Windows;
        using System.Windows.Controls;
    
        namespace AndroidCtrlUI.XTools.Behaviors
        {
            ///<summary>
            /// TreeItemAttach 
            ///<para/> TreeViewItem
            ///</summary>
            public sealed class TreeItemAttach
            {
                #region BringIntoView
    
                ///<summary>
                /// DependencyProperty
                ///</summary>
                public static readonly DependencyProperty BringIntoViewProperty = DependencyProperty.RegisterAttached("BringIntoView", typeof(bool), typeof(TreeItemAttach), new UIPropertyMetadata(false, (s, e) =>
                {
                    if ((bool)e.NewValue != (bool)e.OldValue && s is TreeViewItem t)
                    {
                        if ((bool)e.NewValue)
                        {
                            t.Selected += BringIntoView;
                        }
                        else
                        {
                            t.Selected -= BringIntoView;
                        }
                    }
                }));
    
                ///<summary>
                /// Get
                ///</summary>
                ///<param name="target">DependencyObject</param>
                ///<returns>ICommand</returns>
                public static bool GetBringIntoView(DependencyObject target)
                {
                    return (bool)target.GetValue(BringIntoViewProperty);
                }
    
                ///<summary>
                /// Set
                ///</summary>
                ///<param name="target">DependencyObject</param>
                ///<param name="value">ICommand</param>
                public static void SetBringIntoView(DependencyObject target, bool value)
                {
                    target.SetValue(BringIntoViewProperty, value);
                }
    
                private static void BringIntoView(object sender, RoutedEventArgs e)
                {
                    if (e.Source is TreeViewItem s)
                    {
                        double h = s.ActualHeight;
                        if (s.IsExpanded && s.Items.Count > 0)
                        {
                            h = s.ActualHeight / TreeWalker(s);
                        }
                        s.BringIntoView(new Rect(0, h * -1, s.ActualWidth, h * 2.5));
                    }
                }
    
                private static long TreeWalker(TreeViewItem item)
                {
                    long c = item.Items.Count;
                    foreach (object i in item.Items)
                    {
                        if (i != null && item.ItemContainerGenerator.ContainerFromItem(i) is TreeViewItem t && t.IsExpanded && t.Items.Count > 0)
                        {
                            c += TreeWalker(t);
                        }
                    }
                    return c;
                }
                #endregion
            }
        }
    

    它可以像这样使用:

    <Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
        <Setter Property="tool:TreeItemAttach.BringIntoView" Value="True"/>
    </Style>
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-22
      • 1970-01-01
      • 1970-01-01
      • 2019-12-18
      • 2010-11-21
      • 1970-01-01
      相关资源
      最近更新 更多