[wpf] وف سحب وإسقاط من ليستبوكس مع سيلكتيونمود متعددة


1 Answers

لقد وجدت طريقة بسيطة جدا لتمكين مستكشف ويندوز مثل السحب / إسقاط السلوك عند وجود عناصر متعددة المحددة. الحل يحل محل ListBoxItem المشتركة مع القليل من الرقائق المشتقة التي تحل محل ListBoxItem مع نسخة أكثر ذكاء. بهذه الطريقة، يمكننا تغليف حالة النقر على المستوى الصحيح والدعوة إلى آلات اختيار المحمية من ListBox . هنا هو الطبقة ذات الصلة. للحصول على مثال كامل، انظر الريبو بلدي على جيثب .

public class ListBoxEx : ListBox
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ListBoxItemEx();
    }

    class ListBoxItemEx : ListBoxItem
    {
        private bool _deferSelection = false;

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            if (e.ClickCount == 1 && IsSelected)
            {
                // the user may start a drag by clicking into selected items
                // delay destroying the selection to the Up event
                _deferSelection = true;
            }
            else
            {
                base.OnMouseLeftButtonDown(e);
            }
        }

        protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
        {
            if (_deferSelection)
            {
                try
                {
                    base.OnMouseLeftButtonDown(e);
                }
                finally
                {
                    _deferSelection = false;
                }
            }
            base.OnMouseLeftButtonUp(e);
        }

        protected override void OnMouseLeave(MouseEventArgs e)
        {
            // abort deferred Down
            _deferSelection = false;
            base.OnMouseLeave(e);
        }
    }
}
Question

لقد حصلت على هذا العمل بعيدا عن شيء مزعج قليلا ...

لأن اختيار ليستبوكس يحدث على الماوس لأسفل، إذا قمت بتشغيل السحب مع الماوس لأسفل عند تحديد العنصر الأخير لسحبه يعمل بشكل جيد، ولكن إذا قمت بتحديد كافة العناصر لسحب أولا ثم انقر فوق التحديد لبدء سحبه، واحد النقر على يحصل على إلغاء تحديده وترك وراءها بعد السحب.

أي أفكار حول أفضل طريقة للالتفاف على هذا؟

<DockPanel LastChildFill="True">
    <ListBox ItemsSource="{Binding SourceItems}"
             SelectionMode="Multiple"
             PreviewMouseLeftButtonDown="HandleLeftButtonDown"
             PreviewMouseLeftButtonUp="HandleLeftButtonUp"
             PreviewMouseMove="HandleMouseMove"
             MultiSelectListboxDragDrop:ListBoxExtension.SelectedItemsSource="{Binding SelectedItems}"/>
    <ListBox ItemsSource="{Binding DestinationItems}"
             AllowDrop="True"
             Drop="DropOnToDestination"/>
<DockPanel>

...

public partial class Window1
{
    private bool clickedOnSourceItem;

    public Window1()
    {
        InitializeComponent();
        DataContext = new WindowViewModel();
    }

    private void DropOnToDestination(object sender, DragEventArgs e)
    {
        var viewModel = (WindowViewModel)
                            e.Data.GetData(typeof(WindowViewModel));
        viewModel.CopySelectedItems();
    }

    private void HandleLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        var sourceElement = (FrameworkElement)sender;
        var hitItem = sourceElement.InputHitTest(e.GetPosition(sourceElement))
                      as FrameworkElement;

        if(hitItem != null)
        {
            clickedOnSourceItem = true;
        }
    }

    private void HandleLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        clickedOnSourceItem = false;
    }

    private void HandleMouseMove(object sender, MouseEventArgs e)
    {
        if(clickedOnSourceItem)
        {
            var sourceItems = (FrameworkElement)sender;
            var viewModel = (WindowViewModel)DataContext;

            DragDrop.DoDragDrop(sourceItems, viewModel, DragDropEffects.Move);
            clickedOnSourceItem = false;
        }
    }
}



أنا مندهش أن الفرق السلوك بين ليستبوكس ومستكشف ويندوز لم تؤخذ الرعاية من بعد 4 سنوات عبر 3 التحديثات الرئيسية للإطار. نيت.

ركضت إلى هذه المشكلة مرة أخرى في سيلفرليت 3. انتهى بي الأمر فوق الماوس لأسفل والماوس حتى معالج الحدث لمحاكاة تماما سلوك مستكشف ويندوز.

ليس لدي شفرة المصدر أي أكثر ولكن المنطق يجب أن يكون:

عندما الماوس أسفل

  • إذا لم يتم تحديد العنصر الهدف، مسح التحديد الحالي
    • إذا مفتاح كترل هو أسفل، إضافة عنصر الهدف إلى التحديد
    • إذا مفتاح التحول هو أسفل
      • إذا كان هناك عنصر المحدد سابقا، إضافة كافة العناصر بين البند الهدف والعنصر السابق إلى التحديد
      • وإلا إضافة عنصر الهدف فقط إلى التحديد
  • إذا تم تحديد العنصر المستهدف دي-سيليكت فقط إذا كان مفتاح كترل منخفضا

عندما الماوس حتى (على نفس البند)

  • إذا تم تحديد العنصر المستهدف
    • إذا مفتاح كترل هو أسفل، إزالة العنصر من التحديد
    • إذا مفتاح التحول هو أسفل
      • إذا كان هناك عنصر تم اختياره مسبقا، قم بإزالة كافة العناصر بين العنصر المستهدف والعنصر السابق من التحديد
      • وإلا إزالة العنصر المستهدف فقط من التحديد

ومع ذلك هذا يجب أن يكون حقا وظيفة مايكروسوفت لتحديث السلوك لتكون متسقة مع نظام التشغيل وتكون أكثر سهولة. لقد قدمت أنه خلل إلى ميكروسوفت إذا كان أي هيئة يريد التصويت لذلك: http://connect.microsoft.com/VisualStudio/feedback/details/809192/






Related