【问题标题】:C# WPF Draggable UserControls in ListBox on CanvasC# WPF 可拖动用户控件在 Canvas 上的 ListBox 中
【发布时间】:2011-07-29 22:38:33
【问题描述】:

我有一个列表框中的用户控件,然后将它们托管在画布上。然后,我使用 DraggableExtender(Dragging an image in WPF) 使 UserControls 在画布上可拖动。

但是自从我从 ItemsControl 更改为 ListBox 之后,为了能够使控件可选择,Dragging 的工作真的很糟糕。例如,如果我将一个控件拖动到另一个控件上,则另一个控件将获得焦点并坚持拖动。此外,如果我将鼠标移到画布外,用户控件会卡在边缘并且我失去了拖动焦点,就像 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;
        }
 }

我一直在努力寻找解决方案,但到目前为止我没有成功。有谁知道为什么会发生这种情况以及我该如何解决?

【问题讨论】:

    标签: c# wpf canvas listbox draggable


    【解决方案1】:

    我终于能够弄清楚如何解决这个问题,或者至少如何解决这个问题。问题似乎是 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;
            }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-12-04
      • 1970-01-01
      • 1970-01-01
      • 2018-12-03
      • 2019-09-11
      相关资源
      最近更新 更多