GCiandro
GCiandro

Reputation: 76

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>
       

Upvotes: 3

Views: 1594

Answers (2)

Peter Centellini
Peter Centellini

Reputation: 1575

Although a couple of years since this question was asked, I experienced a similar problem. I had my DataType declared in my App.xaml like this:

<Application.Resources>

    <DataTemplate DataType="{x:Type TypeName=vm:DeviceViewViewModel}">
        <view:DeviceView />
    </DataTemplate>

</Application.Resources>

and no matter how I tried I never got my View to show properly. Only the type/class name, Fusion.UI.Wpf.MVVM.Views.DeviceView.xaml, showed up in the top left corner of my MainWindow as a text string.

When I moved the above code to my MainWindow.xaml code everything works. Really strange to me, and I can add that I've been using this approach, i.e. to declare the DataTypes in my App.xaml, before so I'm totally blown away here, have no clue whatsoever why it doesn't work suddenly, or what I'm missing.

EDIT

I now discovered that if I put an empty call to MergedDictionaries in my App.xaml and keep my DataType declaration in the App.xaml as well everything works, i.e. like this:

<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries />
            
        <DataTemplate DataType="{x:Type TypeName=vm:DeviceViewViewModel}">
            <view:DeviceView />
        </DataTemplate>
    </ResourceDictionary>
</Application.Resources>

That is also the difference between my earlier projects I referred to above, i.e. in those projects I always had a style defined, or had ResourceDictionaries that i referred to in my App.xaml through my ResourceDictionary.MergedDictionaries declaration.

Still I don't understand why it works this way, and why you can't just have a Type declaration without having styling in your App.xaml for it to work.

Upvotes: 0

GCiandro
GCiandro

Reputation: 76

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.

Upvotes: 2

Related Questions