C# WPF 应用程序(组合框)的扩展显示设置中的问题

问题描述 投票:0回答:1

我有双显示器设置。当我在主显示器上打开应用程序并将其拖动到辅助显示器(在两个显示器的中间)并打开应用程序中的组合框时,即使应用程序移至辅助显示器,它也会在主显示器上打开。

Please find image which having both primary and secondary screens

组合框位于主屏幕上,单击鼠标后列表框在辅助屏幕中打开

如果您知道解决此问题的方法,请告诉我。 预先感谢您。

我在这里一无所知。

c# wpf display
1个回答
0
投票

Popup
实际上是真正的
Window
。它与创建它的主屏幕相关联(隐式地通过
ComboBox
)。这就是为什么当您打开
Popup
并开始移动放置目标时,它通常表现得“奇怪”。
Popup
不会跟随。它并非旨在遵循展示位置目标。它是一个独立的“飞行”窗口设计,考虑到了一个非常具体的场景,普通的 Windows(或对话框)无法解决这个问题。通常,您打开它以进行快速操作或简要显示信息(工具提示),并在完成后立即关闭它,至少在将焦点移开时如此。如果您需要像工具箱这样的持久窗口,那么可以使用对话框窗口。关键是
Popup
不遵循放置目标,因此不关心相关的显示更改。
您可以通过更改定位属性(例如
Popup
属性)来强制
Popup.HorizontalOffset
更新其位置。
例如:

HorzontalOffset +=1; 
HorizontalOffset -=1;

这应该将

Popup
移动到新屏幕。例如,您可以实现一个附加行为,当托管
Window
移动时修改偏移量。值得一试。我可以提供以下行为进行尝试。要附加它,您必须引用实际的
Popup
元素。为此,您可以覆盖 ControlTemplate
 的原始 
ComboBox

使用方法

<Popup PopupService.IsSticky="True" />

PopupService.cs

public class PopupService : DependencyObject
{
#region IsFollowPlacementTargetPositionEnabled attached property
  
  public static readonly DependencyProperty IsStickyProperty =
    DependencyProperty.RegisterAttached(
      "IsSticky",
      typeof(bool),
      typeof(PopupService),
      new PropertyMetadata(default(bool), PopupService.OnIsStickyChanged));

  public static void SetIsSticky(DependencyObject attachingElement, bool value) 
    =>
    attachingElement.SetValue(PopupService.IsStickyProperty, value);

  public static bool GetIsSticky(DependencyObject attachingElement) 
    =>
    (bool)attachingElement.GetValue(PopupService.IsStickyProperty);

#endregion

  private static Dictionary<Window, IList<System.Windows.Controls.Primitives.Popup>> WindowToPopupsMap { get; set; }

  static PopupService() 
    => PopupService.WindowToPopupsMap = new Dictionary<Window, IList<System.Windows.Controls.Primitives.Popup>>();

  private static void OnIsStickyChanged(
    DependencyObject attachingElement,
    DependencyPropertyChangedEventArgs e)
  {
    if (attachingElement is not System.Windows.Controls.Primitives.Popup popup)
    {
      throw new ArgumentException("Attaching element must be of type 'System.Windows.Controls.Primitives.Popup'");
    }

    bool isEnabled = (bool)e.NewValue;

    if (isEnabled)
    {
      if (!popup.IsLoaded)
      {
        popup.Loaded += PopupService.EnableFollowTargetMovementOnPopupLoaded;
        return;
      }

      PopupService.EnableFollowTargetMovement(popup);
    }
    else
    {
      PopupService.DisableFollowTargetMovement(popup);
    }
  }

  private static void EnableFollowTargetMovementOnPopupLoaded(object sender, RoutedEventArgs e) 
    => PopupService.EnableFollowTargetMovement(sender as System.Windows.Controls.Primitives.Popup);

  private static void EnableFollowTargetMovement(System.Windows.Controls.Primitives.Popup popup)
  {
    Window window = PopupService.GetParentWindow(popup);
    if (PopupService.WindowToPopupsMap.TryGetValue(window, out IList<System.Windows.Controls.Primitives.Popup> popups)
      && popups != null
      && !popups.Contains(popup))
    {
      popups.Add(popup);
    }
    else
    {
      PopupService.WindowToPopupsMap.Add(window, new List<System.Windows.Controls.Primitives.Popup>() { popup });
    }

    WeakEventManager<Window, EventArgs>.AddHandler(
      window,
      nameof(Window.LocationChanged),
      PopupService.UpdatePopup_OnParentWindowMoved);

    WeakEventManager<Window, SizeChangedEventArgs>.AddHandler(
      window,
      nameof(FrameworkElement.SizeChanged),
      PopupService.UpdatePopup_OnParentWindowSizeChanged);
  }

  private static void DisableFollowTargetMovement(System.Windows.Controls.Primitives.Popup popup)
  {
    Window window = PopupService.GetParentWindow(popup);
    if (PopupService.WindowToPopupsMap.TryGetValue(window, out IList<System.Windows.Controls.Primitives.Popup> popups)
        && !popups.Contains(popup))
    {
      _ = popups.Remove(popup);
      if (!popups.Any())
      {
        _ = PopupService.WindowToPopupsMap.Remove(window);
      }
    }

    WeakEventManager<Window, EventArgs>.RemoveHandler(
      window,
      nameof(Window.LocationChanged),
      PopupService.UpdatePopup_OnParentWindowMoved);

    WeakEventManager<Window, SizeChangedEventArgs>.RemoveHandler(
      window,
      nameof(FrameworkElement.SizeChanged),
      PopupService.UpdatePopup_OnParentWindowSizeChanged);
  }

  private static Window GetParentWindow(System.Windows.Controls.Primitives.Popup popup)
  {
    if (popup.PlacementTarget == null || !popup.PlacementTarget.TryFindVisualParentElement(out Window window))
    {
      window = Application.Current.MainWindow;
    }

    return window;
  }

  private static void UpdatePopup_OnParentWindowMoved(object sender, EventArgs e)
  {
    var window = sender as Window;
    PopupService.UpdatePopupPosition(window);
  }

  private static void UpdatePopup_OnParentWindowSizeChanged(object sender, SizeChangedEventArgs e)
  {
    var window = sender as Window;
    PopupService.UpdatePopupPosition(window);
  }

  private static void UpdatePopupPosition(Window window)
  {
    if (PopupService.WindowToPopupsMap.TryGetValue(window, out IList<System.Windows.Controls.Primitives.Popup> popups))
    {
      foreach (var popup in popups)
      {
        popup.HorizontalOffset += 1;
        popup.HorizontalOffset -= 1;
      }
    }
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.