PleaseWaitWindow Questions

Aug 16, 2011 at 3:03 PM

2 questions:

  1. How can I customize the look of the PleaseWaitWindow? I'm using Telerik's controls to create a simple grid RAD application and the UI freezes while the grid is being measured and rendered. Your spinner is much different looking that Telerik's RadBusyIndicator.
  2. When using Telerik's RadGridView and I click the Filter button to filter a column, it pops up a FilteringControl over the grid to choose the filters I want. When I click any filters in the FilteringControl it re-renders the grid and freezes the UI. PERFECT reason for using your PleaseWaitWindow, but the PleaseWaitWindow is shown UNDER the FilteringControl instead of greying it out and being on top. How can I fix this?

Layering Issue

Aug 16, 2011 at 5:32 PM

I assume that you are using WPF. If not, please let me know.

 

1) You can implement your own version of the PleaseWaitService. Just copy/paste or derive from it to override all its members. Then you can show your own version of the PleaseWaitWindow. Don't forget to register the custom implementation at application startup:

ServiceLocator.Instance.RegisterType<IPleaseWaitService, MyCustomPleaseWaitService>();

2) The filter popup window is probably a separate window. The PleaseWaitWindow of Catel disables the main window of the current process. I *think* that the filtering control is a popup window. What you can do is set a small delay (or force a layout update) to make sure that the filter has time to hide (or does it stay open)?

Aug 16, 2011 at 5:58 PM

It stays open so you can put in multiple selections without having to click it open every time you check one of the boxes. The filtering is triggered as soon as you check a box.

Aug 16, 2011 at 5:59 PM

I will see what I can do, I will let you know ASAP.

Aug 16, 2011 at 6:30 PM

Currently testing if the solution works.

Aug 16, 2011 at 6:35 PM

Just commited a fix that works with my demo app (showing several different non-model dialogs, all now get disabled and the PleaseWaitWindow brings itself to the top).

Aug 16, 2011 at 11:05 PM

Wow that was quick! Are you going to post updated binaries or do I have to download and reference the source?

Thanks.

Aug 17, 2011 at 5:42 AM

The source is not ready for a new release yet, so you'll have to compile the source yourself (shouldn't be too hard, just cleaned up the whole solution to make it easier to understand). Please let me know if the new PleaseWaitWindow behavior works for you.

Aug 17, 2011 at 5:50 AM

For your convenience, I have built an unofficial 2.1 release with all the current changes:

http://dl.dropbox.com/u/8455721/Catel%202.1%20unofficial.zip

For the current changes, take a look at the following page:

http://catel.codeplex.com/SourceControl/changeset/view/1dec7351b8df#doc%2fhistory.txt

Aug 18, 2011 at 2:43 PM

Thank you so much, but it didn't fix it :(

This Telerik FilteringControl is strange, if I set a breakpoint on their Filtering event, the Filtering window seems to be on top of everything, even Windows Explorer windows! See the example below:

Telerik on top

 

Maybe they are hooking into Win32 native code? Anyways, now I noticed a different problem. I attached a behavior to this filtering control so that when I click the Filter button it closes the window (it normally doesn't close it). The code is simple:

void OnFilteringControlLoaded(object sender, RoutedEventArgs e)
{
    // When it loads and all of its children are alive find the "Filter"
    // button which is the only button on the control.
    // You can find out what its name is from the FilteringControl template.
    this.applyFilterButton = this.customFilteringControl.ChildrenOfType<Button>().Where(b => b.Name == "PART_ApplyFilterButton").FirstOrDefault();

    if (this.applyFilterButton != null)
    {
        this.applyFilterButton.Click += this.OnApplyFilter;
    }
}

void OnApplyFilter(object sender, RoutedEventArgs e)
{
    // And when clicked find the parent popup and close it.
    var popup = applyFilterButton.ParentOfType<System.Windows.Controls.Primitives.Popup>();
    if (popup != null)
    {
        popup.IsOpen = false;
    }
}

 

If I call Catel.Windows.PleaseWaitHelper.Show("Please wait..."); during the filtering event the applyFilterButton.Click event is never processed! If I don't call the PleaseWaitHelper.Show it processes the click event handler just fine, do you know why??

Aug 18, 2011 at 3:23 PM

Too bad. I think they set no window as a parent (so it's a system window, which is bad IMHO). It's bad because it cannot be accessed via Application.Current.Windows, which *should* have all windows of the application. It's strange that the please wait window seems to adjust the behavior, it does nothing more then:

1) Disable hittest (you cannot click anywhere)

2) Dimm all the windows registered in the app

3) Undimm all the windows registered in the app

4) Enable hittest again

 

I think the developers of Telerik did some very nasty stuff to get this kind of behavior.

Aug 18, 2011 at 3:31 PM

It does have a parent. I inherited from FilteringControl and can override their Prepare method. If I set a breakpoint there I can see that the parent tree is:

FrameworkElement.Parent = System.Windows.Controls.ContentControl

.Parent = System.Windows.Controls.Primities.Popup

.Parent = System.Windows.Controls.Grid

.Parent = null

Aug 18, 2011 at 3:39 PM

It looks like System.Windows.Controls.Primitives.Popup isn't found by Applicaiton.Current.Windows?

Aug 18, 2011 at 3:48 PM

I will see if there is a way to get all the popups.

Aug 24, 2011 at 1:02 PM

I they are using Popup (which seems to be the case), there is no way to hide this. A popup is a special "window" which is not being registered. If you know a way to get all popups without extensively searching through the visual tree (which is a big hit on the performance), let me know and I will happily add this behavior.

Another way to "solve" this is to make the PleaseWaitWindow a popup as well, but I don't want it to make it system topmost (which telerik seems to do).

Aug 30, 2011 at 10:52 PM

I finally found a way to get all popups! Each WPF Window and each Popup get's it's own Hwnd. You can enumerate all windows using the EnumWindows native function but there's a WPF class which keeps track of these for us. It's called HwndSource, it keeps track of HwndSource's in the CurrentSources property which is just an IEnumerable of HwndSource objects. From there you can get the RootVisual which is a PopupRoot (if the Hwnd is for a Popup, otherwise the RootVisual will be a Window and we ignore it). However, PopupRoot is internal sealed so we convert it to the base FrameworkElement class and get the parent which is Popup! Performance is excellent and this little helper class ought to do it:

public static class PopupHelper
{
    public static List<Popup> Popups { get; set; }

    public static List<Popup> GetAllPopups()
    {
        FindAllPopups();
        return Popups;
    }

    private static void FindAllPopups()
    {
        if (Popups == null)
            Popups = new List<Popup>();
        var sources = HwndSource.CurrentSources.OfType<HwndSource>();
        foreach (var hwndSource in sources)
        {
            if (hwndSource != null)
            {
                var popupRoot = hwndSource.RootVisual as FrameworkElement;
                if (popupRoot != null)
                {
                    Popup popup = popupRoot.Parent as Popup;
                    if (popup != null)
                        Popups.Add(popup);
                }
            }
        }
    }
}

 

Aug 31, 2011 at 7:41 AM

Awesome, I will implement this tonight and send you a new beta version to test if you don't mind.

Aug 31, 2011 at 5:01 PM

Sure thing, let me know when it's ready.

Sep 2, 2011 at 9:52 AM

I created an issue for this so I won't forget this:

http://catel.codeplex.com/workitem/6995