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 showing/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?
views:
52answers:
1
+1
A:
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.
Ray Burns
2010-06-30 02:36:34
I tried your code, but it has these issues:1. Minimize/Maximize by clicking on Taskbar does not invoke Update - I added StateChanged event for this2. In update you are changing visibility of window, I need to change visibility(IsOpen property) of popup on a window.
Nitin Chaudhari
2010-06-30 11:47:53
Dealing with Popup.IsOpen is tricker since you have record the previous state of IsOpen. I added code to do this, and also the StateChanged handler.
Ray Burns
2010-06-30 17:06:10
Well... like I said i can get it working by handling all these events, I was hoping to get a straightforward solution to this problem.. I am sure there are a lot of people out there who need this functionality.
Nitin Chaudhari
2010-07-07 16:30:38