ihtfw
ihtfw

Reputation: 33

View is not shown for singleton ViewModel

I have a wpf application using Caliburn.Micro 2.0.1 and I found strange behaviour of Caliburn.Micro. In latest 3.0.3 it exists too.

Super simple project to reproduce bug: https://github.com/ihtfw/CaliburnMicroBug

MainWindowViewModel is Conductor for Screens. There are two ScreenViewModel as Items for MainWindowViewModel with property SingletonViewModel. In MainViewModel I can switch to first ScreenViewModel or second one.

Everything works perfect except that View for SingletonViewModel is shown only on Second ScreenViewModel after switching to second screen.

To reproduce:

How to fix this?

Update

It's not possible to make these with ContentControl. Should use explicit view. In this case SingletonView and set DataContext of it. To wire up Caliburn.Micro actions bind them without context. So result will be:

<local:SingletonView DataContext={Binding Path=SingletonViewModel} cal:Action.TargetWithoutContext="{Binding}" />

Upvotes: 3

Views: 487

Answers (3)

Nigel Sampson
Nigel Sampson

Reputation: 10609

As stated in the other answers you cannot have a "singleton view", the xaml UI model will not allow the same UI elements to be in the visual tree twice.

What you can do however is have two instances of the same view bound to the view model.

To do this you'll need to sidestep a feature of the framework.

Internally any view model which implements IViewAware holds a weak reference to the view, any time the framework tries to locate the view for a view model it first queries to the view model for that reference.

If a reference is returned then the view is removed from it's existing location and inserted into the new location.

In order to stop this can you do one of three things:

  1. Have your SingletonViewModel not inherit from something that implements IViewAware such as PropertyChangedBase.
  2. Do something really hacky and null out the attached view with the first code sample below.
  3. Change ViewLocator.LocateForModel to remove this behavior with the second code sample below.

Hacky null out view

protected override void OnViewAttached(object view, object context)
{
    Views[context ?? ViewAware.DefaultContext] = null;
}

Remove IViewAware behavior

ViewLocator.LocatorForModel = (model, location, context) => ViewLocator.LocateForModelType(model.GetType(), location, context);

Upvotes: 4

Nawed Nabi Zada
Nawed Nabi Zada

Reputation: 2875

That is not a Bug.

A UIElement such as a UserControl can only have one logical parent.

You are creating two ScreenViews, and you are trying to add the same SingletonView to both of them, which is not possible, because SingletonView cannot have two parents.

Upvotes: 0

Murad
Murad

Reputation: 543

I've worked on your project and found out that your problem is in MainWindows constructor. Change MainWindow's constructor like below:

public MainWindowViewModel()
    {


        Items.Add(new ScreenViewModel
        {
            DisplayName = "Screen 1",
            SingletonViewModel = new SingletonViewModel()
        });

        Items.Add(new ScreenViewModel
        {
            DisplayName = "Screen 2",
            SingletonViewModel = new SingletonViewModel()
        });

        ActiveItem = Items.First();
    }

Upvotes: 0

Related Questions