One Viewmodel reference injected into multiple disappears (possible bug)

Topics: Bugs, Conventions
Jul 12, 2012 at 5:31 PM
Edited Jul 12, 2012 at 5:34 PM

I'm wondering if I should raise this as an issue or just some stupidity on my part.

I'm injecting one viewmodel into multiple Viewmodels that are represented as a collection.

So let's say I have a TabControl and each Tab has the same instance of another ViewModel that I display there (this could be a informationBar about something or whatever).

Now It displays only in the most recent tab. So When I look at Tab1 it's there, if I then go to Tab2 it appears there but now never again in Tab1.

Here is the code to reproduce this problem:

 

    public class ShellViewModel : Conductor<TabViewModel>.Collection.OneActive, IShell
    {
        public ShellViewModel()
        {
            SameInEveryTabViewModel same = new SameInEveryTabViewModel();

            ActivateItem(new TabViewModel("Tab1", same));
            Items.Add(new TabViewModel("Tab2", same));
            Items.Add(new TabViewModel("Tab3", same));
        }
    }
<Window x:Class="CMTest.ShellView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

    <TabControl x:Name="Items" />

</Window>
public class TabViewModel : Screen
    {

        private SameInEveryTabViewModel _same;
        public SameInEveryTabViewModel Same
        {
            get { return _same; }
            set
            {
                _same = value;
                NotifyOfPropertyChange("Same");
            }
        }

        public TabViewModel(string displayName, SameInEveryTabViewModel same)
        {
            DisplayName = displayName;
            this.Same = same;
        }
    }
<UserControl x:Class="CMTest.TabView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        
        <ContentControl x:Name="Same" />
        
        <TextBlock Grid.Row="1" x:Name="DisplayName" FontSize="30" />
        
    </Grid>
</UserControl>
    public class SameInEveryTabViewModel : Screen
    {
        public SameInEveryTabViewModel()
        {
            DisplayName = "Same";
        }
    }
<UserControl x:Class="CMTest.SameInEveryTabView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <TextBlock x:Name="DisplayName" />
    </Grid> 
</UserControl>

If I would skip with defining SameInEveryTabViewModel in a seperate view and just do it right there in the TabView then it would work fine with a normal old style binding. But of course you would wan't to be able to define it seperatly because SameInEveryTabViewModel might not always be the same.

Is this a Issue that I should put in the Issue tracker?

Nov 14, 2012 at 12:40 PM

I had the same problem in combination with MEF. Adding the PartCreationPolicy solved it:

 

[Export]
[PartCreationPolicy(System.ComponentModel.Composition.CreationPolicy.NonShared)]
public class SameInEveryTabViewModel : Screen {...}
 

 

Maybe it helps?

 

Nov 14, 2012 at 1:24 PM

Note that CM caches the view associated to a view-model, in case it implements IViewAware.

This means that the same view is always re-used for IViewAware-derived objects, hence you can encounter some issues when referencing the same view-model in different places. The code provided by kittof will produce different view-models every time an instance of SameInEveryTabViewModel is required, but if you really need the same instance in multiple places, then you need to disable view-caching for that view-model.