开发者

WPF creating window-popup

开发者 https://www.devze.com 2023-01-05 14:59 出处:网络
By window-popup I mean a popup which sort of stays only with a window/application. As far as I know I will have to explicitly handle show开发者_StackOverflow中文版ing/hiding of popup based on Applicat

By window-popup I mean a popup which sort of stays only with a window/application. As far as I know I will have to explicitly handle show开发者_StackOverflow中文版ing/hiding of popup based on

Application.Current.Activated/Deactivated

Application.Current.MainWindow.Activated/Deactivated

ParentWindow.Activated/Deactivated

I want to make sure Alt-Tab hides/shows the popup, win-D hides popup, switching between windows in the same application should do nothing, restoring/maximizing from taskbar should show popup.

I have written handlers for all those events, and they are killing me, why is this such a irritating issue. There has to be a simple way to handle this. Any ideas?


A single event handler should suffice for the entire job.

First in your App.xaml add a Window style that sets the event handler using an attached property:

<Style TargetType="Window">
  <Setter Property="local:PopupWindowControl.AttachHandler" Value="true" />
</Style>

Mark all of your windows that need the special behavior:

<Window local:PopupWindowControl.HideWhenAppInactive="true" ... >

Now you just need to create the attached properties and an update method

  • "HideWhenAppInactive" is a bool attached property used to mark Windows and Popups. It also maintains a record of all Popups with this property set.
  • "AttachHandler" is a bool attached property with a PropertyChangedCallback that attaches the handler.
  • "Update" is a method that updates the visibility of Windows and Popups based on whether there is an visible & active window

It would look something like this:

public class PopupWindowControl : DependencyObject
{
  // HideWhenAppInactive
  public static bool GetHideWhenAppInactive(DependencyObject obj) { return (bool)obj.GetValue(HideWhenAppInactiveProperty); }
  public static void SetHideWhenAppInactive(DependencyObject obj, bool value) { obj.SetValue(HideWhenAppInactiveProperty, value); }
  public static readonly DependencyProperty HideWhenAppInactiveProperty = DependencyProperty.RegisterAttached("HideWhenAppInactive", typeof(bool), typeof(PopupWindowControl), new PropertyMetadata
    {
      PropertyChangedCallback = (obj, e) =>
        {
          if((bool)e.NewValue && obj is Popup)
          {
            if((_cleanupCounter++ % 10000) == 0)
              _hideWhenInactivePopups = (from weakRef in _hideWhenInactivePopups where weakRef.IsAlive select weakRef).ToList();

            _hideWhenInactivePopups.Add(new WeakReference(obj));
          }
        }
    });

  // AttachHandler
  public static bool GetAttachHandler(DependencyObject obj) { return (bool)obj.GetValue(AttachHandlerProperty); }
  public static void SetAttachHandler(DependencyObject obj, bool value) { obj.SetValue(AttachHandlerProperty, value); }
  public static readonly DependencyProperty AttachHandlerProperty = DependencyProperty.RegisterAttached("AttachHandler", typeof(bool), typeof(PopupWindowControl), new PropertyMetadata
  {
    PropertyChangedCallback = (obj, e) =>
    {
      if((bool)e.NewValue)
      {
        var window = (Window)obj;
        window.Activated += Update;
        window.Deactivated += Update;
        window.StateChanged += Update;
      }
    }
  });

  private static void Update(object sender, EventArgs e)
  {
    var active =
      Application.Current.Windows.OfType<Window>().Where(win =>
        win.IsActive &&
        win.Visibility==Visibility.Visible &&
        win.WindowState != WindowState.Minimized)
        .Any();

    // First update Windows marked HideWhenAppInactive
    foreach(var popupWindow in Application.Current.Windows.OfType<Window>().Where(win => GetHideWhenAppInactive(win)))
      popupWindow.Visibility = active ? Visibility.Visible : Visibility.Hidden;

    // Then update Popups marked HideWhenAppInactive
    if(active && _temporarilyHiddenPopups!=null)
    {
      foreach(var popup in _temporarilyHiddenPopups)
        popup.IsOpen = true;
      _temporarilyHiddenPopups = null;
    }
    else if(!active)
    {
      if(_temporarilyHiddenPopups==null) _temporarilyHiddenPopups = new List<Popup>();
      foreach(var popup in
        (from weak in _hideWhenInactivePopups 
         let popup = weak.Target as Popup
         where popup!=null && popup.IsOpen && GetHideWhenAppInactive(popup)
         select popup))
      {
        _temporarilyHiddenPopups.Add(popup);
        popup.IsOpen = false;
      }
    }
  }

  private static List<WeakReference> _hideWhenInactivePopups = new List<WeakReference>();
  private static List<Popup> _temporarilyHiddenPopups;
  private static int _cleanupCounter;
}

Note that I didn't add any code to detach the handler when "AttachHandler" or "HideWhenAppInactive" are set to false since for this purpose they will never be used that way.

0

精彩评论

暂无评论...
验证码 换一张
取 消