为什么我WPF应用程序的第一次启动显示ViewModel类名而不是其内容(属性)?

3

我将MainWindowViewModel绑定到MainWindow的DataContext上。 然后我将这个MainWindowViewModel初始化为特定的itemsPageViewModel

问题在于,启动时我看到的是itemsPageViewModel的类名,而不是它的内容: Startup

然而,在通过按钮(RelayCommands)切换页面之后,同一个ViewModel现在显示其内容: PageSwitched

两个操作都经过同一行代码:

CurrentPageViewModel = _itemsPageViewModel

为什么会产生不同的结果呢?

代码

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;


        }

    }
}
<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>

1
将ContentControl的Content设置为ViewModel并不会像View一样神奇地创建一个控件。一些MVVM框架,如Caliburn,可以自动完成此操作,但这不是标准的WPF行为。 - Euphoric
感谢大家的反馈。我刚刚添加了缺失的文件,用于定义我的viewModel的数据模板。我通过另一个xaml文件进行了定义:这是正确的方式吗? - GCiandro
是的,如果引用了字典。 - Babbillumpa
@Babbillumpa 是的,它是来自app.xaml的引用。 - GCiandro
所以在 App.xaml 文件中,你是否有以下代码?<ResourceDictionary> <ResourceDictionary.MergedDictionaries> <ResourceDictionary Source="YourDictionary"/> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> - Babbillumpa
显示剩余5条评论
1个回答

1
我们采用了一个解决特定问题的变通方法。我们选择不使用资源字典,直接将viewModel的数据模板放入mainwindow.xaml中:现在一切都有效了。当我们使用资源字典时会发生一些奇怪的事情。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接