【问题标题】:Why the first launch of my WPF application shows the class name of a ViewModel instead of its content (properties)?为什么我的 WPF 应用程序的第一次启动显示 ViewModel 的类名而不是其内容(属性)?
【发布时间】:2018-12-26 11:22:45
【问题描述】:

我将 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;


        }

    }
}

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>

【问题讨论】:

  • 将 ContentControl 的内容设置为 ViewModel 不会让它神奇地创建一个控件作为视图。一些 MVVM 框架,如 Caliburn 会自动执行此操作,但这不是标准的 WPF 行为。
  • 感谢大家的反馈。我刚刚添加了为我的 viewModel 定义数据模板的缺失文件。我通过另一个 xaml 定义它:这是正确的方式吗?
  • @GiovanniCiandrini 是的,如果引用了字典。
  • @Babbillumpa 是的。它是来自 app.xaml 的参考
  • 所以在 App.xaml 里面你有 .... ?

标签: c# wpf xaml mvvm viewmodel


【解决方案1】:

我们使用了一种解决方法来解决这个特定问题。 我们选择不使用资源字典,将 viewModel 的 dataTemplates 直接放入 mainwindow.xaml:现在一切正常。 当我们使用资源字典时会发生一些奇怪的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    相关资源
    最近更新 更多