Нарисовать Button при клике на окно WPF

250
05 июля 2017, 23:53

Я хочу сделать приложение : юзер кликает и зажимает мышку, а когда он её отпускает, рисуется Button у которого левый верхний угол это координаты клика (событие MouseDown), а правый нижний - координаты места где пользователь отпустил кнопку мыши (событие MouseUp). Вот код для MouseDown:

private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e)
{
    StartPoint = e.GetPosition(this);
    //Свойство StartPoint объявляется сверху таким образом
    //private System.Windows.Point StartPoint { get; set; }
}

Вот код для MouseUp:

private void MainWindow_MouseUp(object sender, MouseButtonEventArgs e)
{
     EndPoint = e.GetPosition(this);
     //Свойство EndPoint объявляется сверху таким образом
     //private System.Windows.Point EndPoint { get; set; }
     Button temp = new Button();
     temp.Margin = new Thickness(StartPoint.X, StartPoint.Y, EndPoint.X, EndPoint.Y);
     temp.Background = new SolidColorBrush(Colors.Blue);
     temp.Content = "Do not click me!";
     mainGrid.Children.Add(temp);
}

Это не работает, кнопки рисуются слишком большими или вообще не рисуются. Что я делаю не так и как сделать так, чтобы это заработало?

Answer 1
  1. Координаты надо считать для того контрола, куда вкладываете кнопку. К данном случае для грида.
  2. Маргин справа и снизу - это не координаты, это расстояние от края контрола до края кнопки (в вашем случае)

Немного переписал ваш код

    private void MainWindow_MouseDown(object sender, MouseButtonEventArgs e)
    {
        StartPoint = e.GetPosition(mainGrid);
        //Свойство StartPoint объявляется сверху таким образом
        //private System.Windows.Point StartPoint { get; set; }
    }

    private void MainWindow_MouseUp(object sender, MouseButtonEventArgs e)
    {
        EndPoint = e.GetPosition(mainGrid);
        //Свойство EndPoint объявляется сверху таким образом
        //private System.Windows.Point EndPoint { get; set; }           
        Button temp = new Button();
        temp.Margin = new Thickness(StartPoint.X, StartPoint.Y, mainGrid.ActualWidth - EndPoint.X, mainGrid.ActualHeight - EndPoint.Y);
        temp.Background = new SolidColorBrush(Colors.Blue);
        temp.Content = "Do not click me!";
        mainGrid.Children.Add(temp);
    }
Answer 2

Для того, чтобы располагать контролы по абсолютным координатам, правильно использовать Canvas, он для этого специально предназначен. Поэтому я бы написал так:

XAML:

<Grid>
    <Canvas MouseLeftButtonDown="OnCanvasLeftMouseDown" Background="Transparent"/>
</Grid>

Code-behind:

void OnCanvasLeftMouseDown(object sender, MouseButtonEventArgs eDown)
{
    var canvas = (Canvas)sender;
    var startPos = eDown.GetPosition(canvas);
    canvas.MouseLeftButtonUp += OnUp;
    void OnUp(object _, MouseButtonEventArgs eUp) // захватим позицию начала
    {
        canvas.MouseLeftButtonUp -= OnUp;
        var endPos = eUp.GetPosition(canvas);
        var button = new Button()
        {
            Content = "Do not click me!",
            Width = Math.Abs(endPos.X - startPos.X),
            Height = Math.Abs(endPos.Y - startPos.Y)
        };
        Canvas.SetLeft(button, Math.Min(startPos.X, endPos.X));
        Canvas.SetTop(button, Math.Min(startPos.Y, endPos.Y));
        canvas.Children.Add(button);
    }
}

С подачи @tym32167, более строгий вариант:

void OnCanvasLeftMouseDown(object sender, MouseButtonEventArgs eDown)
{
    var canvas = (Canvas)sender;
    var startPos = eDown.GetPosition(canvas);
    canvas.MouseLeftButtonUp += OnUp;
    canvas.Unloaded += Unsubscribe;
    Mouse.Capture(canvas);
    void OnUp(object _, MouseButtonEventArgs eUp) // захватим позицию начала
    {
        Mouse.Capture(null);
        Unsubscribe(_, eUp);
        var endPos = eUp.GetPosition(canvas);
        if (!canvas.IsMouseOver)
            return;
        var button = new Button()
        {
            Content = "Do not click me!",
            Width = Math.Abs(endPos.X - startPos.X),
            Height = Math.Abs(endPos.Y - startPos.Y)
        };
        Canvas.SetLeft(button, Math.Min(startPos.X, endPos.X));
        Canvas.SetTop(button, Math.Min(startPos.Y, endPos.Y));
        canvas.Children.Add(button);
    }
    void Unsubscribe(object _, RoutedEventArgs e)
    {
        canvas.MouseLeftButtonUp -= OnUp;
        canvas.Unloaded -= Unsubscribe;
    }
}

Добавлен захват мыши, чтобы отпускание её происходило в том же контексте. Также добавлена подписка на выгрузку Canvas'а, на случай, если логика UI выгрузит его до отпускания мыши.

Answer 3
    private void Grid_PreviewMouseDown(object sender, MouseButtonEventArgs e) {
        Mouse.Capture(sender as IInputElement);
    }
    private void Grid_PreviewMouseUp(object sender, MouseButtonEventArgs e) {
        Point upPoint = e.GetPosition(sender as Grid);
        if (upPoint.X < 0 || upPoint.X > mainGrid.ActualWidth ||
            upPoint.Y < 0 || upPoint.Y > mainGrid.ActualHeight)
            return;
        Mouse.Capture(null);
        Button button = new Button();
        button.Margin = new Thickness(upPoint.X, upPoint.Y, 0, 0);
        button.VerticalAlignment = VerticalAlignment.Top;
        button.HorizontalAlignment = HorizontalAlignment.Left;
        button.Background = new SolidColorBrush(Colors.Blue);
        button.Content = "Do not click me!";
        button.Width = 120;
        button.Height = 20;
        mainGrid.Children.Add(button);
    }
READ ALSO
T4 не видит пространство имен

T4 не видит пространство имен

В сгенерированный класс попадает Null Подскажите почему не видит?

179
Binding элемента Combobox к строке в DataGrid WPF(Связь с БД по Entity Framework)

Binding элемента Combobox к строке в DataGrid WPF(Связь с БД по Entity Framework)

Столкнулся с такой проблемой, что не получается нормально прибайндить комбобокс к базе данныхИмеется код:

237
Как удалить дубликаты (string) с помощью C#?

Как удалить дубликаты (string) с помощью C#?

ЗдравствуйтеЕсть такой массив

242
Как добавить native dll в проект в Visual Studio 2012

Как добавить native dll в проект в Visual Studio 2012

Проект, написанный на языке C#Среда: Visual Studio 2012

265