Как сделать Popup подвижным в C# WPF более одного раза?

Я создал пользовательский элемент управления, который использует

        <UserControl .......           
         MouseMove = "UserControl_MouseMove" 
         MouseLeftButtonUp = "UserControl_MouseLeftButtonUp">

Мой раздел PopUp кода:

<Popup Name = "CustomTablePopup" Placement = "Center" IsOpen = "False" PopupAnimation = "Slide" MouseLeftButtonDown = "CustomTablePopup_MouseLeftButtonDown" AllowsTransparency = "True">
        <Border x:Name = "roundBorder" BorderThickness = "0" CornerRadius = "10" Background = "Yellow">
          <Border.Effect>
            <DropShadowEffect Color = "Black" Direction = "-360" ShadowDepth = "40" Opacity = "0.7" />
          </Border.Effect>
          
          <Grid Width = "Auto" Height = "Auto" Background = "White">
            <Grid.RowDefinitions>
                <RowDefinition Height = "40"/>
                <RowDefinition Height = "*"/>
            </Grid.RowDefinitions>

            <!-- PopUp Header -->
            <!-- Style for the Border Colour -->
            <Rectangle Grid.Row = "0" Fill = "Gold" Opacity = "0.8"/>
            <Grid x:Name = "GridHeader" Grid.Row = "0">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width = "250"/>
                    <ColumnDefinition Width = "*"/>
                    <ColumnDefinition Width = "Auto"/>
                    <ColumnDefinition Width = "200"/>
                </Grid.ColumnDefinitions>

                <!-- PopUp Window Buttons -->
                <Border Grid.Column = "3" HorizontalAlignment = "Right">
                    <Grid Background = "Gold" Opacity = "0.8">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width = "Auto"/>
                            <ColumnDefinition Width = "Auto"/>
                            <ColumnDefinition Width = "Auto"/>
                        </Grid.ColumnDefinitions>

                        <Button Style = "{DynamicResource HeaderButtonStyle}" Grid.Column = "2" Background = "Transparent" BorderBrush = "Transparent" Click = "CloseButton_Click">
                            <StackPanel Orientation = "Horizontal">
                                <Image RenderOptions.BitmapScalingMode = "HighQuality" Source = "/Resources/close-window-image.png"/>
                            </StackPanel>
                        </Button>
                    </Grid>
                </Border>
            </Grid>

            <Grid Grid.Row = "1">
                <Grid.RowDefinitions>
                    <RowDefinition Height = "*"/>
                    <RowDefinition Height = "*"/>
                </Grid.RowDefinitions>

                <Label Grid.Row = "1" Content = "This is the Custom Table Popup"/>
            </Grid>
            
            </Grid>
        </Border>
</Popup>

и я создал одноэлементный класс, который обновляется только после изменения параметра:

public class PopUpMovement
{
    private PopUpMovement() { }

    private static PopUpMovement _instance;
    private static readonly object _instanceLock = new object();

    public static PopUpMovement Instance()
    {
        if (_instance == null)
        {
            lock (_instanceLock)
            {
                if (_instance == null)
                {
                    _instance = new PopUpMovement();
                }
            }
        }

        return _instance;
    }

    public bool draggingPopup { get; set; }
    public bool CustomTablePopupClicked { get; set; }
}

Мой код в коде usercontrol:

    private Point startPoint;
    private double initialHorizontalOffset;
    private double initialVerticalOffset;
    private Point initialMousePosition;
    private Point startDragPoint;
    //private bool CustomTablePopupClicked;

    public UserControlPage()
    {
        InitializeComponent();
        CustomTablePopup.MouseMove += UserControl_MouseMove;
        CustomTablePopup.MouseLeftButtonDown += CustomTablePopup_MouseLeftButtonDown;
        CustomTablePopup.MouseLeftButtonUp += UserControl_MouseLeftButtonUp;
    } 

    private void CloseButton_Click(object sender, RoutedEventArgs e)
    {
        if (CustomTablePopup.IsOpen == true)
        {
            CustomTablePopup.IsOpen = false;
        }
    }

    private void UserControl_MouseMove(object sender, MouseEventArgs e)
    {

        if (PopUpMovement.Instance().draggingPopup)
        {
            else if (PopUpMovement.Instance().CustomTablePopupClicked)
            {
                Point currentMousePosition = e.GetPosition(this); // Get the mouse position relative to the UserControl
                double offsetX = currentMousePosition.X - initialMousePosition.X;
                double offsetY = currentMousePosition.Y - initialMousePosition.Y;

                CustomTablePopup.HorizontalOffset += offsetX;
                CustomTablePopup.VerticalOffset += offsetY;

                initialMousePosition = currentMousePosition; // Update initial position
            }
        }
    }

    private void UserControl_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (PopUpMovement.Instance().draggingPopup == true)
        {
            PopUpMovement.Instance().draggingPopup = false;
            PopUpMovement.Instance().CustomTablePopupClicked = false;
            Mouse.Capture(null);
        }
    }


    private void CustomTablePopup_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        // Store the mouse position
        //draggingPopup = true;
        //PopUpMovement popUpMovement = PopUpMovement.Instance();
        //popUpMovement.draggingPopup = true;
        PopUpMovement.Instance().draggingPopup = true;
        initialMousePosition = e.GetPosition(this); // Get the mouse position relative to the Window
        Mouse.Capture(this); // Capture mouse at the UserControl level
    }

Это работает нормально, если пользователь перемещает всплывающее окно в первый раз, однако, если пользователь хочет переместить его снова, ничего не происходит, оно остается фиксированным. Итак, как я могу исправить код, чтобы пользователь мог перемещать всплывающее окно куда угодно?

Зачем этот Синглтон? Опасно хранить данные, связанные с экземплярами (необщие данные) других объектов, в одном элементе, который в основном разделяет все. Каждый может перезаписать это состояние. Этот вид программирования склонен к ошибкам. Вам следует создать новые экземпляры PopUpMovement. Если вы хотите поделиться PopUpMovement, явно поделитесь этим экземпляром. Кроме того, лучше использовать Lazy<T> для создания общего экземпляра Singleton. Но не используйте здесь Singleton. Это не имеет никакого смысла и только открывает двери для ошибок.

BionicCode 13.07.2024 00:09

Свойства PopUpMovement действительно должны быть членами UserControl. Класс «А» никогда не должен хранить состояние другого класса «Б». Каждый класс должен управлять своим состоянием (за исключением того, что класс «А» является структурой данных).

BionicCode 13.07.2024 00:18

Мы говорим о перетаскивании элемента управления Popup или вы создаете собственное всплывающее окно? Является ли UserControl всплывающим окном? Что такое CustomTablePopup? Это Popup?

BionicCode 13.07.2024 00:19

@BionicCode, спасибо за комментарии. Моя цель — сделать всплывающее окно перетаскиваемым, мне удалось этого добиться, если я попытаюсь переместить его в первый раз. Однако, если я попробую еще раз, этого не произойдет, оно останется зафиксированным на том месте, где я оставил всплывающее окно. Да, «CustomTablePopup» — это всплывающее окно в коде xaml.

NeoGenesis521 13.07.2024 09:59
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
83
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Чтобы создать перетаскиваемый элемент Popup, сначала необходимо прикрепить обработчики событий непосредственно к элементу Popup. Затем обеспечьте цель перетаскивания, обернув содержимое Popup в Border с Border.Background, установленным на Transparent (или любую другую кисть. Просто убедитесь, что значение не равно null). Если для Popup.AllowsTransparency установлено значение true, фон Transparent не подойдет.

Затем вы должны отфильтровать выбранный элемент: например, вы не хотите перетаскивать Popup, если пользователь нажимает на TextBox. Вместо этого вы хотели бы разрешить TextBox выбирать текст.

<UserControl>
  <Popup IsOpen = "True"
         PreviewMouseDown = "Popup_PreviewMouseDown"
         PreviewMouseMove = "Popup_PreviewMouseMove">
    <Border Background = "White"
            Padding = "8">
      <TextBox Text = "I'm a Popup" />
    </Border>
  </Popup>
</UserControl>
    private Point lastDragPosition;
    private bool isDragging;
    
private void Popup_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
  this.isDragging = e.OriginalSource is FrameworkElement clickedElement 
    && clickedElement.Parent is Popup;
  if (!this.isDragging)
  {
    return;
  }

  this.lastDragPosition = e.GetPosition(this);
}

private void Popup_PreviewMouseMove(object sender, MouseEventArgs e)
{
  if (!this.isDragging 
    || e.LeftButton is MouseButtonState.Released)
  {
    return;
  }

  Point currentDragPosition = e.GetPosition(this);
  double horizontalOffset = currentDragPosition.X - this.lastDragPosition.X;
  double verticalOffset = currentDragPosition.Y - this.lastDragPosition.Y;
  this.lastDragPosition = currentDragPosition;

  var popup = (Popup)sender;
  popup.HorizontalOffset += horizontalOffset;
  popup.VerticalOffset += verticalOffset;
}

Я изменил вопрос, включив в него код xaml для моего всплывающего окна.

NeoGenesis521 15.07.2024 09:50

Я вежливо попросил вас опубликовать минимальный воспроизводимый пример. Вместо этого вы продолжаете публиковать фрагменты кода, которые даже не компилируются. Вам не хватает закрывающих тегов, ваши операторы if полностью сломаны, и вы не показали, как установлен соответствующий CustomTablePopupClicked. Вам действительно трудно помочь вам. Либо используйте мой код и интегрируйте его в свое приложение, либо опубликуйте минимальный воспроизводимый пример. Бессмысленно просматривать сломанные фрагменты кода без их контекста. Я не могу сказать, что такое опечатки, а что на самом деле ошибки. Также покажите, как вы показываете/скрываете всплывающее окно.

BionicCode 15.07.2024 11:13

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

BionicCode 15.07.2024 11:13

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

BionicCode 15.07.2024 11:16

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

NeoGenesis521 15.07.2024 11:26

Да, но ваш код неполный. Также интересно, как вы показываете/скрываете всплывающее окно, поскольку это также может повлиять на поведение вашего кода. Мне нужен весь соответствующий код, чтобы правильно его просмотреть. Дело не в ваших расчетах. Однако спасибо за понимание того, что проверка кода возможна только тогда, когда показан весь связанный код и сам код можно собрать.

BionicCode 15.07.2024 11:30

Я снова отредактировал вопрос. Достаточно ли этих сведений, чтобы воспроизвести проблему и предоставить информацию о том, в чем может быть проблема?

NeoGenesis521 15.07.2024 11:49

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

NeoGenesis521 15.07.2024 12:55

Рад, что у вас получилось. Но видите? Я спросил об этом конкретном контексте кода обработки CustomTablePopupClicked, и теперь это стало причиной. Если бы вы показали этот код с самого начала, мы бы решили вашу проблему несколько дней назад. Теперь вы должны понять, насколько важны детали. Какой хороший урок вы усвоили :)

BionicCode 15.07.2024 13:13

Тем не менее, я рад, что вы это исправили. Желаем приятно провести время и насладиться своим проектом.

BionicCode 15.07.2024 13:14

Другие вопросы по теме