4

I'm using MVVM via Caliburn Micro on WP7. I have a popup that is shown from the VM. On the popup is a performance progress bar. The progress bar does not show when IsIndeterminate is set to true because the popup is not in the visual tree (it is a custom control).

If I grab the view from the view model and force the popup into the visual tree the progress bar displays correctly. I don't really want to do this though.

What is the best way to do this whilst preserving the separation of view and view model. Is there some way the popup can insert itself into the root page or frame?

Steve Chadbourne
  • 6,873
  • 3
  • 54
  • 82

3 Answers3

1

The way I approach this is with a child view model/controller/event source exposed by the view model and bound to the control.

The control can listen for events on the source to do it's work, it's nicely separated and even unit testable.

A good example of this is my Status Indicator Control, the view model exposes a StatusSource with methods such as Display and Clear. The control itself is bound to the source and listens for changes. From there you can do anything, including creating the popup and inserting it into the visual tree.

Nigel Sampson
  • 10,549
  • 1
  • 28
  • 31
  • Good idea - will put a child VM between the page VM and the control. I still need a way the popup can insert itself into the visual tree. I should be able to do something with the RootVisual - either PhoneApplicationPage or PhoneApplicationFrame. This way the popup can be used anywhere. Just can't see how to do this? – Steve Chadbourne Mar 07 '11 at 22:15
  • As far as I can tell from the little I've worked with Popup that it's not really part of the visual tree at all (which can cause issues with orientation). You can create a Popup, set it's child to your control and then call show without adding to the visual tree. An example of that is at http://devlicio.us/blogs/derik_whittaker/archive/2010/08/27/creating-a-toast-like-notification-popup-on-wp7.aspx – Nigel Sampson Mar 07 '11 at 22:29
  • Yes you can, and that is what I was doing, but then I added a progress bar and it didn't work. As soon as I added the popup to the visual tree the progress bar started working. – Steve Chadbourne Mar 07 '11 at 22:47
  • Strange, I haven't run into that problem, sorry I can't be more help. – Nigel Sampson Mar 07 '11 at 22:55
0

Are you working with a designer? I've found that doing anything view-based in code, other than loading data, confuses and/or frustrates them. I would recommend creating 2 visual states, one with the popup shown and one hidden, so that the designer can see what the app looks like and can toggle (and style) the popup in Blend. I then use the DataStateBehavior or DataStateSwitchBehavior to control the popup from my VM.

karl.r
  • 961
  • 1
  • 11
  • 28
  • The popup itself shows and hides fine. The progress bar does not work though. I need a generic way of inserting the popup into the visual tree. Once I have got that I can create a base popup control that my other popups can inherit from. – Steve Chadbourne Mar 07 '11 at 22:18
0

I ended up creating a base popup class and adding this code in:

private void HookIntoPage()
{
    if (UserControlHelper.RootVisual != null)
    {
        PhoneApplicationPage page = (PhoneApplicationPage)UserControlHelper.RootVisual.Content;

        // Hook up into the back key press event of the current page
        page.BackKeyPress += BackKeyPress;

        FrameworkElement element = page.FindVisualChild("MainGrid");

        if (element != null && element is Grid)
        {
            Grid grid = element as Grid;
            grid.Children.Add(this);
        }
        else
        {
            throw new Exception("Popup cannot find MainGrid");
        }
    }
}

It's a bit hard coded as it looks for a MainGrid grid control. This could be improved to look for an appropriate top level container.

There are 2 helper classes at play here. UserControlHelper has the following methods:

public static PhoneApplicationFrame RootVisual
{
    get
    {
        return Application.Current == null ? null : Application.Current.RootVisual as PhoneApplicationFrame;
    }
}

FindVisualChild comes from a VisualTreeHelperExtension class that came with Phone7.Fx.preview that I use for its bindable app bar.

Steve Chadbourne
  • 6,873
  • 3
  • 54
  • 82