C # WPF Dragable UserControls в ListBox на холсте - PullRequest
1 голос
/ 05 апреля 2011

У меня есть UserControls, которые у меня есть в ListBox, который затем размещает их на холсте.Затем я сделал перетаскивание UserControls на холсте с помощью DraggableExtender ( Перетаскивание изображения в WPF ).

Но с тех пор, как я перешел с ItemsControl на ListBox, чтобы можно было сделатьвыбираемые элементы управления, перетаскивание работает очень плохо.Например, если я перетаскиваю элемент управления на другой элемент управления, другой элемент управления становится сфокусированным и придерживается перетаскивания.Также, если я перемещаю мышь за пределы холста, пользовательский контроль застревает на краю, и я теряю перетаскивающий фокус, как будто CaptureMouse не работает.

ListBox выглядит следующим образом (когда он работал до того, как был ItemsControl):

<ListBox ItemsSource="{Binding Components}" SelectedItem="{Binding SelectedItem}" Background="Transparent">
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <Canvas ClipToBounds="True" Height="{Binding CurrentProject.Height, Converter={StaticResource SizeConverter}}"
                            Width="{Binding CurrentProject.Width, Converter={StaticResource SizeConverter}}" 
                            HorizontalAlignment="Left" VerticalAlignment="Top">
                        <Canvas.Background>
                            <SolidColorBrush Color="{DynamicResource {x:Static SystemColors.WindowFrameColorKey}}"/>
                        </Canvas.Background>
                    </Canvas>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
            <ListBox.ItemContainerStyle>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="HorizontalAlignment" Value="Stretch" />
                    <Setter Property="Background" Value="Transparent" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                                <Grid>
                                    <Border Background="{TemplateBinding Background}" />
                                    <ContentPresenter/>
                                </Grid>
                                <ControlTemplate.Triggers>
                                    <MultiTrigger>
                                        <MultiTrigger.Conditions>
                                            <Condition Property="IsMouseOver" Value="True" />
                                            <Condition Property="IsSelected" Value="False"/>
                                        </MultiTrigger.Conditions>
                                        <Setter Property="Background" Value="#8868D5FD" />
                                    </MultiTrigger>
                                    <Trigger Property="IsSelected" Value="True">
                                        <Setter Property="Background" Value="#4468D5FD" />
                                    </Trigger>
                                </ControlTemplate.Triggers>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                    <Setter Property="Utils:DraggableExtender.CanDrag" Value="True" />
                    <Setter Property="Canvas.Top" Value="{Binding Path=Conveyor.Y, Converter={StaticResource SizeConverter},Mode=TwoWay}" />
                    <Setter Property="Canvas.Left" Value="{Binding Path=Conveyor.X, Converter={StaticResource SizeConverter},Mode=TwoWay}" />
                </Style>
            </ListBox.ItemContainerStyle>
        </ListBox>

Мой DraggableExtender выглядит следующим образом:

public class DraggableExtender : DependencyObject
    {
        public static readonly DependencyProperty CanDragProperty = 
            DependencyProperty.RegisterAttached("CanDrag", typeof(bool), typeof(DraggableExtender), 
            new UIPropertyMetadata(false, OnChangeCanDragProperty));

        private static bool isDragging = false;
        private static Point offset;

        public static void SetCanDrag(UIElement element, bool o)
        {
            element.SetValue(CanDragProperty, o);
        }

        public static bool GetCanDrag(UIElement element, bool o)
        {
            return (bool)element.GetValue(CanDragProperty);
        }

        private static void OnChangeCanDragProperty(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            UIElement element = d as UIElement;
            if (element == null) return;

            if (e.NewValue != e.OldValue)
            {
                if ((bool)e.NewValue)
                {
                    element.PreviewMouseDown += element_PreviewMouseDown;
                    element.PreviewMouseUp += element_PreviewMouseUp;
                    element.PreviewMouseMove += element_PreviewMouseMove;
                }
                else
                {
                    element.PreviewMouseDown -= element_PreviewMouseDown;
                    element.PreviewMouseUp -= element_PreviewMouseUp;
                    element.PreviewMouseMove -= element_PreviewMouseMove;
                }
            }
        }

        private static void element_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            if (element == null) return;
            Debug.WriteLine(element);

            isDragging = true;
            element.CaptureMouse();
            offset = e.GetPosition(element);
        }

        private static void element_PreviewMouseMove(object sender, MouseEventArgs e)
        {
            if (!isDragging) return;

            FrameworkElement element = sender as FrameworkElement;
            if (element == null) return;

            Canvas canvas = element.FindAncestor<Canvas>();
            if (canvas == null) return;

            Point mousePoint = e.GetPosition(canvas);

            mousePoint.Offset(-offset.X, -offset.Y);

            element.SetValue(Canvas.LeftProperty, mousePoint.X);
            element.SetValue(Canvas.TopProperty, mousePoint.Y);
        }

        private static void element_PreviewMouseUp(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            if (element == null) return;
            element.ReleaseMouseCapture();
            isDragging = false;
        }
 }

Я пытался найти решение, но до сих пор мне не удалось.У кого-нибудь есть идеи, почему это происходит и как я могу это решить?

1 Ответ

0 голосов
/ 14 апреля 2011

Я наконец-то смог выяснить, как решить эту проблему, или, по крайней мере, сделать обходной путь. Кажется, проблема в том, что ListBox также захватывает мышь внутри своего кода выбора. Поэтому я изменил, добавив e.Handled = true, чтобы ListBox не получал событие и, таким образом, не перекрывал мышиный захват. Это сделало механизм выбора непригодным для использования, но чтобы обойти это, я переместил свой код только для прослушивания события MouseRight, что означает, что когда я щелкаю левой кнопкой мыши, я выбираю, а когда я щелкаю правой кнопкой мыши, я могу перетаскивать.

private static void element_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {
            FrameworkElement element = sender as FrameworkElement;
            if (element == null) return;
            Debug.WriteLine(element);

            isDragging = true;
            element.CaptureMouse();
            offset = e.GetPosition(element);
            e.Handled = true;
        }
...