Всплывающее окно не появляется

Недавно мы переместили наше приложение WPF в dot net 6 и обнаружили, что один из элементов управления не работает. Это своего рода настраиваемый элемент управления полем со списком, который работает как всплывающее окно для кнопки, поэтому всякий раз, когда мы нажимаем на кнопку, отображается всплывающее окно, но после миграции оно не отображается.

// this is the control that is supposed to popup on button click
public class BalonCtrl : ContentControl
{
  static BalonCtrl()
  {
    DefaultStyleKeyProperty.OverrideMetadata(typeof(BalonCtrl), 
    new FrameworkPropertyMetadata(typeof(BalonCtrl)));
  }

  // some properties like 

  public void Show()
  {
    var popup = new PopUp()
    {
      RenderTransform = new ScaleTransform(App.Window.ApplicationScale, App.Window.ApplicationScale),
      Focusable = true,
      MinWidth = MinWidth,
      PlacementTarget = Target as FrameworkElement,
      Child = this, // <== Delegate the Content to the Popup so that it can render it
      AllowsTransparency = true,
      StaysOpen = false,
      Placement = Placement,
      PlacementRectangle = PlacementRectangle,
      PopupAnimation = PopupAnimation.Slide
    };

     popup.isOpen = true;
  }

}

// Вот как вызывается приведенный выше фрагмент кода

onButtonclick()
{
 
 var list = new windows.ComboBoxPopup();

 var balloon = new windows.BalonControl()
 {
   Content = list,
 };

ballon.show();


}



Когда я удаляю контент, который является свойством контента в классе ContentControl, из объекта воздушного шара и устанавливаю список в качестве дочернего непосредственно в методе показа BallononControl, всплывающее окно работает, проблема заключается только в стиле.

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

Стоит ли изучать 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 называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
57
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Не похоже, что это имеет какое-либо отношение к .NET 6. Скорее это похоже на ошибку рефакторинга.

Дело в том, что BalloonControl — это ContentControl. Чтобы его было видно, он должен быть дочерним элементом визуального дерева (что BalloonControl не является). Единственный шанс отобразить какой-либо контент — делегировать его Popup, который BalloonControl создаёт и показывает. Но ты никогда этого не делаешь. Вместо этого вы устанавливаете Popup.Child для самого экземпляра BalloonControl. Просто исправьте инициализацию Popup.

Важно!
В настоящее время вы создаете потенциальную утечку памяти для BalloonControl. Если вы сохраните ссылку на экземпляр BalloonControl и снова вызовете Show, старый Popup не будет собирать мусор, потому что обработчики событий BalloonControl поддерживают его активность. Чтобы быть в безопасности на будущее (когда вы забыли об этих деталях или когда другие разработчики, которые не знают деталей реализации, используют этот код), вам следует: а) использовать WeakEventManager для прослушивания событий Popup или б) отменить регистрацию всех обработчики событий из события Popup.Closed или c) повторно использовать Popup и обновлять только свойство Popup.Child (время жизни Popup и BalloonControl теперь одинаковое).

Исправления, примененные к вашему примеру:

public class BalloonControl : ContentControl
{
  static BalloonControl()
  {
    DefaultStyleKeyProperty.OverrideMetadata(typeof(BalloonControl), new FrameworkPropertyMetadata(typeof(BalloonControl)));
  }

  // some properties like 

  public void Show()
  {
    var popupContent = this.Content;
    this. Content = null;
    _Popup = new Popup()
    {
      RenderTransform = new ScaleTransform(App.Window.ApplicationScale, App.Window.ApplicationScale),
      Focusable = true,
      MinWidth = MinWidth,
      PlacementTarget = Target as FrameworkElement,
      Child = popupContent, // <== Delegate the Content to the Popup so that it can render it
      AllowsTransparency = true,
      StaysOpen = false,
      Placement = Placement,
      PlacementRectangle = PlacementRectangle,
      PopupAnimation = PopupAnimation.Slide
    };

    this.SizeChanged += OnSizeChanged;
    _Popup.Opened += OnPopupOpened;
    _Popup.Closed += OnPopupClosed;
    _Popup.IsOpen = true;
  }

  private void OnPopupOpened(object sender, EventArgs e)
  {
    Mouse.Capture(_Popup.Child, CaptureMode.SubTree);
    // right now up or down only
    if (PointerOrientation == Common.PointerOrientation.Bottom)
    {
      var target = Target as FrameworkElement;
      if (target != null)
      {
        Point pt = target.TranslatePoint(PlacementRectangle.TopLeft, Content as FrameworkElement);
        if (pt.Y > 0)
        {
          PointerOrientation = Common.PointerOrientation.Top;
        }
      }
    }
  }

  private void OnPopupClosed(object sender, EventArgs e)
  {
    this.SizeChanged -= OnSizeChanged;
    _Popup.Opened -= OnPopupOpened;
    _Popup.Closed -= OnPopupClosed;

    if (IsCancelled)
    {
      if (OnCancel != null) OnCancel(this, new EventArgs());
    }
    else
    {
      if (OnApply != null) OnApply(this, new EventArgs());
    }
  }

  private void OnSizeChanged(object sender, SizeChangedEventArgs e) 
  {
    if (Placement == PlacementMode.Top || Placement == PlacementMode.Bottom)
    {
      if (UseCanvasScale)
      {
        Graphic.GraphicCanvas canvas = Graphic.GraphicCanvas.FocusedCanvas;
        _Popup.HorizontalOffset = (-e.NewSize.Width / 2) / canvas.CanvasScale.ScaleX;
      }
      else
      {
        _Popup.HorizontalOffset = -e.NewSize.Width / 2;
      }
    }
  }
}

Я тоже попробовал, но у меня возникла ошибка, поскольку указанный элемент является логическим дочерним элементом другого элемента. Я знаю, почему это происходит, единственное решение, которое я могу придумать, — это создать отдельное свойство и назначить его дочернему элементу. В этом случае всплывающее окно, кажется, работает. Единственное, чего я не понимаю, и причина, по которой я думаю, что это проблема dot net 6, заключается в том, что тот же код правильно работал в предыдущей версии, которая была 4.8.

PrabDev 03.07.2024 17:08

Вы должны установить для свойства Content значение NULL. Я обновлю пример.

BionicCode 03.07.2024 17:35

Вы уверены, что это был тот самый код? Невозможно, чтобы это когда-либо работало. Невозможный.

BionicCode 03.07.2024 17:37

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

PrabDev 03.07.2024 19:31

Решат ли мои предложения вашу проблему? Что касается вашего сломанного исходного кода. Если этот код никогда не трогался, проблема в чем-то другом. Вам что-нибудь не хватает? Может быть, вам не хватает стиля BalloonControl по умолчанию, который должен быть определен в Generic.xaml? Всплывающее окно может отображать BalloonControl только в том случае, если был найден стиль по умолчанию или стиль переопределения. Это объясняет, почему всплывающее окно ничего не показывает. Код, который вы показали, настолько прост. Убежден, что это не связано со сменой целевых рамок. Убедитесь, что стиль по умолчанию находится в правильном файле Generic.xaml.

BionicCode 03.07.2024 23:34

Спасибо за предложение, позвольте мне посмотреть на это и вернуться к вам.

PrabDev 04.07.2024 10:54

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

PrabDev 08.07.2024 11:07

Таким образом, всплывающее окно может отображать содержимое элемента управления всплывающим окном в предыдущей версии, но не в dot net 6. Этот элемент управления всплывающим окном используется в другом месте, где содержимое отличается, и там оно также не работает, хотя в предыдущие версии.

PrabDev 08.07.2024 11:09

Действительно сложно сказать, не зная подробностей. Я вполне убежден, что это не имеет ничего общего с целевой версией платформы (за исключением того, что вы не предоставили важную информацию). Единственное разумное объяснение, которое у меня есть, это то, что вы пропустили стиль по умолчанию в Genric.xaml. Вы можете попытаться реконструировать проблему. Создайте пустой проект, нацеленный на используемую в данный момент платформу и который, по вашему мнению, сломал ваш код. Затем переместите управление в этот проект. и использовать его там. Это просто всплывающее окно. Ничего особенного. Я ожидал, что все будет работать как обычно.

BionicCode 08.07.2024 13:50

Затем добавьте дополнительный код, чтобы воспроизвести использование в вашем текущем приложении (например, внешний ресурс или дополнительные стили и т. д.). В какой-то момент вы снова сможете выйти из-под контроля. Если вам удалось создать минимальный воспроизводимый пример, вы можете создать репозиторий GitHub, чтобы я мог просмотреть ваш контроль и соответствующий контекст. Я почти уверен, что проблема в некоторых мелких деталях, которые заставляют вас смеяться, когда вы понимаете, что все это было перед вашими глазами.

BionicCode 08.07.2024 13:51

Вы были правы, это была только проблема со стилем, в основном стиль Balloon Control указан неправильно.

PrabDev 09.07.2024 11:58

Хороший. Я рад, что смог помочь во всем разобраться.

BionicCode 09.07.2024 13:49

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