Search code examples
c#wpfxamlmvvmviewmodel

Why the first launch of my WPF application shows the class name of a ViewModel instead of its content (properties)?


I bind a MainWindowViewModel to the DataContext of a MainWindow. Then I initialize this MainWindowViewModel to a specific itemsPageViewModel.

The problem is that on startUp I see itemsPageViewModel 's class name instead of its content: Startup

However, after switching pages through buttons (RelayCommands), the same ViewModel now shows its content: PageSwitched

Both operations pass through the same code-line:

CurrentPageViewModel = _itemsPageViewModel

How can it produce different results?

CODE

MainWindow.xaml

 <Window x:Class="ListItemUI.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="ListItemUI" Height="400" Width="600">
    <Grid>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="10"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>

            <Grid Grid.Row="0">
                <StackPanel Orientation="Horizontal">
                    <Button Content="ITEMS" Margin="2" Command ="{Binding SelectItemsPageViewModel}"></Button>
                    <Button Content="HELP" Margin="2" Command ="{Binding SelectInfoPageViewModel}"></Button>
                </StackPanel>
            </Grid>

            <ContentControl Grid.Row="2" Content="{Binding CurrentPageViewModel}"/>
      
    </Grid>
 </Grid>
</Window>

MainWindow.xaml.cs

using System.Windows;
using ListItemUI.InfoPage.ViewModels;
using ListItemUI.ListItemPage.ViewModels;
using ListItemUI.ViewModels;

namespace ListItemUI.Views
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow(IPageFactory itemPageFactory, IPageFactory infoPageFactory)
        {
            InitializeComponent();
            var mainWindowVM = new MainWindowViewModel(itemPageFactory,infoPageFactory);
            DataContext = mainWindowVM;
        }
    }
}

MainWindowViewModel.cs

using System;
using System.Windows.Input;
using ListItemUI.ListItemPage.ViewModels;

namespace ListItemUI.ViewModels
{
    public class MainWindowViewModel : ViewModelBase
    {
        private readonly IListItemUIViewModel _itemsPageViewModel;
        private readonly IListItemUIViewModel _infoPageViewModel;
        public ICommand SelectItemsPageViewModel { get; }
        public ICommand SelectInfoPageViewModel { get; }

        
        public object CurrentPageViewModel
        {
            get { return _currentPageViewModel; }
            set
            {
                _currentPageViewModel = value;
                 RaisePropertyChanged(() => CurrentPageViewModel);
            }
        }
        private object _currentPageViewModel;


        public MainWindowViewModel(IPageFactory itemsPageFactory, IPageFactory infoPageFactory)
        {
            _itemsPageViewModel = itemsPageFactory.CreatePage();
            _infoPageViewModel = infoPageFactory.CreatePage();
           

            SelectItemsPageViewModel = new RelayCommand(_ =>
            {
                    CurrentPageViewModel = _itemsPageViewModel;
                     
            });

            SelectInfoPageViewModel = new RelayCommand(_ =>
            {
                CurrentPageViewModel = _infoPageViewModel;
            });

            CurrentPageViewModel = _itemsPageViewModel;


        }

    }
}

ListItemPage.xaml (dataTemplates)

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:viewModels ="clr-namespace:ListItemUI.ListItemPage.ViewModels">

    <DataTemplate DataType="{x:Type viewModels:ItemViewModel}">
        <StackPanel>
            <TextBlock Foreground="RoyalBlue" FontWeight="Bold" Text="{Binding Path=ItemViewDescription, StringFormat='Group Info = {0}'}"></TextBlock>
        </StackPanel>
    </DataTemplate>

    <DataTemplate DataType="{x:Type viewModels:ItemsPageViewModel}">
        <StackPanel>
            <TextBlock Text ="{Binding Path=Title}"></TextBlock>
            <Grid Grid.Column="0" Background="Aquamarine">
            <ListBox ItemsSource="{Binding Path=LocalItemViewModels}" Margin="5">
            </ListBox>
        </Grid>
        </StackPanel>
    </DataTemplate>
</ResourceDictionary>

App.xaml

<Application x:Class="ListItemUI.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Application.Resources>

         <ResourceDictionary>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="ListItemPage/Views/ListItemPage.xaml"></ResourceDictionary>
                 <ResourceDictionary Source="InfoPage/Views/InfoView.xaml"></ResourceDictionary>
                 <!--GLOBAL RESOURCES -->
                 <ResourceDictionary Source="Views/GlobalResources.xaml"></ResourceDictionary>
             </ResourceDictionary.MergedDictionaries>
         </ResourceDictionary>
    </Application.Resources>
</Application>
       

Solution

  • We used a workaround to solve this specific problem. We chose not to use resource dictionaries, putting the dataTemplates of the viewModels directly into the mainwindow.xaml: now everything works. Something strange happens when we use resource dictionaries.