Pass a control to an action

Jan 16, 2011 at 3:39 PM

I have a context menu that will rename an item in a list.  I have a usercontrol that should popup and have a text box and a button for user to enter a new name.  The usercontrol has a method called Open which will show the popup.  So, I want to be able to pass the control to my action and I want to call the Open method on it.

Here is the XAML

 <StackPanel x:Name="LayoutRoot" Background="Transparent" d:LayoutOverrides="Width, Height">
                <ItemsControl x:Name="Notes" Margin="0,0,-12,0" >
                    <ItemsControl.ItemTemplate >
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17" Width="432" cal:Message.Attach="[Event MouseLeftButtonUp] = [Action GoToNote($datacontext)]" >
                                <toolkit:ContextMenuService.ContextMenu>
                                    <toolkit:ContextMenu cal:Action.TargetWithoutContext="{Binding DataContext, ElementName=LayoutRoot}">
                                        <toolkit:MenuItem Header="Rename" cal:Message.Attach="Rename"></toolkit:MenuItem>
                                        <toolkit:MenuItem Header="Delete" cal:Message.Attach="Delete($datacontext)" />
                                    </toolkit:ContextMenu>
                                </toolkit:ContextMenuService.ContextMenu>
                                <Border BorderThickness="1">
                                    <TextBlock Text="{Binding Name}"/>
                                </Border>
                            </StackPanel>

                        </DataTemplate>
                    </ItemsControl.ItemTemplate>

                </ItemsControl>

            </StackPanel>
            <RenameControl x:Name="MyRenameControl"/>

Here is how my action might look like

public void Rename(Note sender, RenameControl ctl)
{
    ctl.Open(sender);
}

How do I do that?

Jan 16, 2011 at 6:20 PM

You can use this.GetView(null) to obtain the reference of the view associated to the current VM; then you can obtain the control from the view by name.

As a cleaner solution, you might consider creating a specific RenameNoteViewModel, along with an associated RenameNoteView (containing the textbox and the confirmation button).

Then you can initialize the new view model:

theRenameVM = new RenameNoteViewModel(); //you might also get a factory from the container to build an instance
theRenameVM.Initialize(sender);

Once you have a VM set up, you can display it in a popup using IWindowManager.ShowPopup method.
Using this approach you don't have to access the view direclty, leaving your VM easily testable. 

Jan 16, 2011 at 6:36 PM

That helps, but where is the ShowPopup method?   It doesn't exist.  By the way, I am on a Windows Phone app.

Coordinator
Jan 16, 2011 at 6:39 PM

Unfortunately, there is not window manager in the WP7 version currently.

Jan 17, 2011 at 9:23 AM

Ops...
(@Rob: there is a problem with the popup implementation in WP7?)

Anyway, to overcome the limitation you might expose the RenameVM as a property in the parent VM, then bind the content of the Popup as usual.
To control Popup visibility you might use a (bound) bool property of the root VM.

You might also turn your action into a coroutine and use a custom IResult along this line to show the new VM in a popup:

	public class PopupResult : IResult
	{
		//... constructor omitted;
	
		//passed or loaded in the constructor
		IScreen screenToShow; 
		
		public void Execute(ActionExecutionContext context)
		{
			var content = new ContentControl();
			Caliburn.Micro.View.SetModel(content, screenToShow);
			var popup = new Popup { 
				Child = content
			};
			popup.Closed += delegate { screenToShow.Deactivate(true); };
			popup.IsOpen = true;
			Completed(this, new ResultCompletionEventArgs());
		}

		public event EventHandler<ResultCompletionEventArgs> Completed = delegate { };
	}

Coordinator
Jan 17, 2011 at 2:44 PM

I feel that cleanly adding a window manager service to the WP7 version of the framework at this point in time is just too much work for me to think about. If someone wants to give it a go and submit the .cs file, I'll consider adding it. One of the big problems is in the ChildWindow support. That makes it difficult to do ShowModal. I'd need to investigate heavily the touch support to see if there is an easy way to show a popup like in SL/WPF. I just haven't take the time to look into all of that.

Jan 17, 2011 at 5:15 PM

Sorry, I justt realized you were refering to the whole WindowManager, not just ShowPopup method.
Actually, I never happened to use WindowManager on WP7; it might not make much sense for the platform, all in all.