WPF C # Как сделать элемент управления перетаскиваемым с помощью мыши - PullRequest
0 голосов
/ 22 апреля 2019

Я пытаюсь создать пользовательский элемент управления, который перемещается по холсту. Я использую C # и WPF. Я вижу много примеров в сети, но мне просто нужен минимум.

Я нашел статью: «Перетаскиваемый элемент управления в WPF»

Кто-то ответил:

Если вы хотите сделать это руками, используйте следующий алгоритм:

При событии MouseDown: сохранить положение мыши, положение элемента управления TopLeft и дельту (смещение) этих координат и установить некоторый флаг логического поля, например. IsDragStartted для истины. На MouseMove проверьте, что перетаскивание началось, и используйте положение и смещение мыши, чтобы вычислить новое значение положения элемента управления TopLeft

При событии MouseUp для IsDragStarted установлено значение false


У меня возникли проблемы с применением этого.

открытый частичный класс UserControl1: UserControl {

    private Point startingMousePosition;
    private Point endingMousePosition;
    private Point startingControlPosition;
    bool isDragStarted;

    public UserControl1()
    {
        InitializeComponent();

    }

    private void Grid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if(!isDragStarted)
        {
            startingControlPosition.X = Canvas.GetLeft(this);
            startingControlPosition.Y = Canvas.GetTop(this);

            startingMousePosition.X = e.GetPosition(this.Parent as Canvas).X;
            startingMousePosition.Y = e.GetPosition(this.Parent as Canvas).Y;
        }



    }

    private void Grid_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            isDragStarted = true;

            if (isDragStarted)
            {

                endingMousePosition.X = e.GetPosition(this.Parent as Canvas).X;
                endingMousePosition.Y = e.GetPosition(this.Parent as Canvas).Y;

                Canvas.SetLeft(this, endingMousePosition.X - startingControlPosition.X);
                Canvas.SetTop(this, endingMousePosition.Y - startingControlPosition.Y);

            }
        }

    }



    private void Grid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {

        isDragStarted = false;
    }



}

Вот мой код для формы WPF главного окна:

{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{

    UserControl1 userCTL;
    public MainWindow()
    {
        InitializeComponent();

        userCTL = new UserControl1();
        userCTL.Width = 50;
        userCTL.Height = 100;
        Canvas.SetTop(userCTL,20);
        Canvas.SetLeft(userCTL, 20);

        CanvasMain.Children.Add(userCTL);

    }

    private void Window_Loaded(object sender, RoutedEventArgs e)
    {
        AdornerLayer myAdornerLayer = AdornerLayer.GetAdornerLayer(userCTL);
        if (myAdornerLayer != null)
        {
            myAdornerLayer.Add(new SimpleCircleAdorner(userCTL));
        } 
    }




}
* *} Тысяча двадцать-один

Вот мой код WPF для главного окна:

<Window x:Class="WpfApplicationEvent.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="374.306" Width="594.271" Loaded="Window_Loaded">
<Grid>
    <ScrollViewer Margin="46,23,74,33" PanningMode="Both" HorizontalScrollBarVisibility="Visible">
        <Canvas x:Name="CanvasMain" Height="395" Width="506">

        </Canvas>
    </ScrollViewer>

</Grid>
</Window>

Я также попытался разместить украшения, чтобы в итоге изменить размер элемента управления. это ни к чему не привело, как получили украшатели, но они ничего не делают.

У меня есть все мои элементы управления перетаскиванием в моем UserControl1, который я создал, и я получил его для перетаскивания, но когда я снова щелкаю экземпляр UserControl1, чтобы перетащить его во второй раз, он сбрасывается в местоположения SetTop (0) и SetLeft (0). Он так странно прыгает! Я ожидал перетаскивания экземпляра UserControl1 в положение курсора. Он делает это с первой попытки, но затем я щелкаю UserControl1, чтобы перетащить его еще раз, и он переходит к (0,0) или близко к нему.

1 Ответ

0 голосов
/ 22 апреля 2019

У вас здесь есть пара проблем ...

  1. Обработчик события PreviewMouseDown должен быть добавлен в ваш дочерний элемент управления, иначе вы не будете знать, какой объект вы перетаскиваете.
  2. Вы собираетесь перетаскивать родительский Canvas, поэтому добавьте к нему обработчик MouseMove.
  3. Вызовите CaptureMouse () снова для элемента управления Canvas и сохраните его во время перетаскивания.
  4. Рассчитайте положение мыши относительно верхнего левого угла перетаскиваемого элемента управления, а затем примените это смещение в обратном порядке при каждой установке положения.Это удерживает точку, которую вы щелкнули под курсором мыши во время перетаскивания, и останавливает его «прыжок» на новую позицию, что раздражает пользователя.

Таким образом, ваш XAML-холст теперь должен выглядеть следующим образомэто:

<Canvas x:Name="CanvasMain" Height="395" Width="506"
    PreviewMouseMove="CanvasMain_PreviewMouseMove"
    PreviewMouseUp="CanvasMain_PreviewMouseUp" />

И ваш код должен выглядеть следующим образом:

public MainWindow()
{
    InitializeComponent();

    var userCTL = new UserControl();    // <-- replace with your own control
    userCTL.Background = Brushes.Blue;  // <-- added this so I can see it
    userCTL.Width = 50;
    userCTL.Height = 100;
    Canvas.SetTop(userCTL, 20);
    Canvas.SetLeft(userCTL, 20);
    userCTL.PreviewMouseDown += UserCTL_PreviewMouseDown;

    CanvasMain.Children.Add(userCTL);
}

UIElement dragObject = null;
Point offset;

private void UserCTL_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    this.dragObject = sender as UIElement;
    this.offset = e.GetPosition(this.CanvasMain);
    this.offset.Y -= Canvas.GetTop(this.dragObject);
    this.offset.X -= Canvas.GetLeft(this.dragObject);
    this.CanvasMain.CaptureMouse();
}

private void CanvasMain_PreviewMouseMove(object sender, MouseEventArgs e)
{
    if (this.dragObject == null)
        return;
    var position = e.GetPosition(sender as IInputElement);
    Canvas.SetTop(this.dragObject, position.Y - this.offset.Y);
    Canvas.SetLeft(this.dragObject, position.X - this.offset.X);
}

private void CanvasMain_PreviewMouseUp(object sender, MouseButtonEventArgs e)
{
    this.dragObject = null;
    this.CanvasMain.ReleaseMouseCapture();
}

Вы также можете добавить обработчик MouseLeave к Canvas, чтобы пользователь не перетаскивал элементы управления за пределы области.видимая клиентская область.

...