PRX
PRX

Reputation: 137

Setting Caliburn.Micro ControlContent from another ViewModel

I'm new to Caliburn.Micro (and MVVM for that matter) and I'm trying to Activate a screen with my conductor located in ShellViewModel from a button within a sub-viewmodel (one called by the conductor). All the tutorials I've seen have buttons in the actual shell that toggle between so I'm a little lost.

All the ViewModels share the namespace SafetyTraining.ViewModels

The ShellViewModel (first time ever using a shell so I might be using it in the wrong manner)

public class ShellViewModel : Conductor<object>.Collection.OneActive, IHaveDisplayName
{        
    public ShellViewModel()
    {
        ShowMainView();
    }

    public void ShowMainView()
    {
        ActivateItem(new MainViewModel());
    }
}

ShellView XAML

<UserControl x:Class="SafetyTraining.Views.ShellView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel>
    <ContentControl x:Name="ActiveItem" />
</DockPanel>

MainViewModel - the main screen (does correctly display).

public class MainViewModel : Screen
{
    public void ShowLoginPrompt()
    {
        LoginPromptViewModel lg = new LoginPromptViewModel();//This does happen
    }
}

MainView XAML

<Button cal:Message.Attach="[Event Click] = [ShowLoginPrompt]">Login</Button> 

LoginPromptViewModel

public class LoginPromptViewModel : Screen
{
    protected override void OnActivate()
    {
        base.OnActivate();
        MessageBox.Show("Hi");//This is for testing - currently doesn't display
    }
}

EDIT Working Code:

Modified Sniffer's code a bit to properly fit my structure. Thanks :)

var parentConductor = (Conductor<object>.Collection.OneActive)(this.Parent);
        parentConductor.ActivateItem(new LoginPromptViewModel());

Upvotes: 1

Views: 1519

Answers (1)

Ibrahim Najjar
Ibrahim Najjar

Reputation: 19423

You are doing everything correctly, but you are missing one thing though:

public void ShowLoginPrompt()
{
    LoginPromptViewModel lg = new LoginPromptViewModel();//This does happen
}

You are creating an instance of LoginPromptViewModel, but you are not telling the conductor to activate this instance, so it's OnActivate() method is never called.

Now before I give you a solution I should suggest a couple of things:

  1. If you are using the MainViewModel to navigate between different view-models then it would be appropriate to make MainViewModel a conductor itself.

  2. If you aren't using it like that, then perhaps you should put the button that navigates to the LoginPromptViewModel in the ShellView itself.

Now back to your problem, since your MainViewModel extends Screen then it has a Parent property which refers to the Conductor, so you can do it like this:

public void ShowLoginPrompt()
{
    LoginPromptViewModel lg = new LoginPromptViewModel();//This does happen
    var parentConductor = (Conductor)(lg.Parent);
    parentConductor.Activate(lg);
}

Upvotes: 2

Related Questions