Для всей работы достаточно одного обработчика событий.
Сначала в вашем App.xaml добавьте стиль Window, который устанавливает обработчик событий с помощью присоединенного свойства:
<Style TargetType="Window">
<Setter Property="local:PopupWindowControl.AttachHandler" Value="true" />
</Style>
Отметьте все свои окна, для которых требуется специальное поведение:
<Window local:PopupWindowControl.HideWhenAppInactive="true" ... >
Теперь вам просто нужно создать вложенные свойства и метод обновления
- «HideWhenAppInactive» - это прикрепленное к bool свойство, используемое для пометки окон и всплывающих окон. Также поддерживается запись всех всплывающих окон с этим набором свойств.
- «AttachHandler» - это подключенное свойство bool с PropertyChangedCallback, который присоединяет обработчик.
- «Обновление» - это метод, который обновляет видимость Windows и всплывающих окон в зависимости от наличия видимого и активного окна
Это будет выглядеть примерно так:
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;
}
Обратите внимание, что я не добавил никакого кода для отсоединения обработчика, когда «AttachHandler» или «HideWhenAppInactive» установлены в false, поскольку для этой цели они никогда не будут использоваться таким образом.