MVVM无法在主页

时间:2016-09-05 21:51:39

标签: c# wpf mvvm

我正在使用WPF创建应用并尝试使用MVVM模式。

我有一个主窗口设置了一些在应用程序中使用的默认控件 在这个主窗口中,我有一个ContentControl设置来显示不同的子视图,具体取决于按下的导航按钮。

在大多数情况下,这很好用。实际的导航功能正常,所以我不太关心该代码。将显示主窗口,当我按下按钮时,将显示所需的ContentControl,其中包含来自数据库的正确信息。

我遇到的问题是尝试显示默认的ContentControl。当MainWindow首次加载时,我想要" Master"无需按下按钮即可显示ContentControl。

这就是我现在所拥有的:

MainWindowVM:

public class MainWindowVM : ViewModelBase
{
    public MainWindowVM()
    {
        NavCommand = new NavigationCommand<string>(OnNav);
    }

    private MasterViewVM masterViewVM = new MasterViewVM();
    private Room1ViewVM room1ViewVM = new Room1ViewVM();
    private Room2ViewVM room2ViewVM = new Room2ViewVM();

    private ObservableObject currentViewModel;
    public ObservableObject CurrentViewModel
    {
        get { return currentViewModel; }
        set { SetProperty(ref currentViewModel, value); }
    }

    public NavigationCommand<string> NavCommand { get; private set; }

    private void OnNav(string destination)
    {
        switch (destination)
        {
            case "master":
                CurrentViewModel = masterViewVM;
                break;
            case "room1":
                CurrentViewModel = room1ViewVM;
                break;
            case "room2":
                CurrentViewModel = room2ViewVM;
                break;
        }
}

主窗口XAML:

<Window.Resources>
    <DataTemplate DataType="{x:Type viewModels:MasterViewVM}">
        <views:MasterView/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewModels:Room1ViewVM}" >
        <views:Room1View />
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewModels:Room2ViewVM}" >
        <views:Room2View />
    </DataTemplate>
</Window.Resources>

<Grid>
    <StackPanel Name="stackPage" Orientation="Vertical" Grid.Column="1">

        <StackPanel Name="stackNavButtons"
                Orientation="Horizontal"
                Grid.Column="1" Grid.ColumnSpan="4"
                Grid.Row="1"
                HorizontalAlignment="Center"
                VerticalAlignment="Center"
                >
            <Button Name="btnMaster"
            Content="Master"                    
            Height="50"
            Width="75"
            Command="{Binding NavCommand}"
            CommandParameter="master"
            />
            <Button Name="btnRoom1"
            Content="Room 1"                    
            Height="50"
            Width="75"
            Command="{Binding NavCommand}"
            CommandParameter="room1"
            />
            <Button Name="btnRoom2"
            Content="Room 2"                    
            Height="50"
            Width="75"
            Command="{Binding NavCommand}"
            CommandParameter="room2"
            />
        </StackPanel>

        <ContentControl Content="{Binding CurrentViewModel}" />

    </StackPanel>
</Grid>

我尝试将这些行(单独)添加到MainWindowVM构造函数中。

  • CurrentViewModel = masterViewVM;
  • CurrentViewModel = new MasterViewVM();
  • OnNav(&#34;主&#34);

我尝试过的各种方法最终导致System.NullReferenceException指向ObservableObject(由ViewModelBase引用)帮助器类。具体来说,它指向:

  

PropertyChanged(this,new PropertyChangedEventArgs(propertyName));

和状态&#34;对象引用未设置为对象的实例&#34;。

我怀疑问题是当我加载MainWindow时,Master的数据尚未填充。我认为那就是给我空引用的东西。

以下是打开MainWindow的代码(来自主页上的按钮):

    public ICommand OpenMainCommand
    {
        get { return new RelayCommand(p => OpenMainWindow()); }
    }

    private void OpenMainWindow()
    {
        MainWindow mainWin = new MainWindow();
        MainWindowVM mainVM = new MainWindowVM();
        mainWin.DataContext = mainVM;
        mainWin.Show();
    }

我尝试在上面的方法中添加以下内容,试图在打开主窗口之前加载数据(并尝试显示主窗口)。

        MasterView masterView = new MasterView();
        MasterViewVM masterVM = new MasterViewVM();
        masterView.DataContext = masterVM;

我尝试的最后一件事是完全重建程序,并遵循Rachel Lim博客中关于Navigation in MVVM的指导。 我不会在这里包含修改后的代码,因为我最终得到了相同的结果。

我能够让Rachel的示例应用程序正常运行。但是,它没有连接到数据库。这进一步表明我的问题在于何时和/或如何将我的数据加载到主视图中。

我现在要做的就是让主人在显示MainWindow时显示为初始ContentControl。

编辑:更改&#34; currentViewModel&#34; (根据ibebbs的建议,大写到小写)解决了这个问题。 现在构造函数读取:

    public MainWindowVM()
    {
        NavCommand = new NavigationCommand<string>(OnNav);
        currentViewModel = masterViewVM;
    }

由于这也有问题,这里是我的ObservableObject的代码:

public class ObservableObject : INotifyPropertyChanged
{

    protected virtual void SetProperty<T>(ref T member, T val, [CallerMemberName] string propertyName = null)
    {
        if (object.Equals(member, val)) return;

        member = val;
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

我将最后一部分(也是每个ibebbs)修改为: (注意:我的问题在没有这种修改的情况下得到了解决。)

    protected void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
    {
        if (PropertyChanged == null)
            return;
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

我不确定这是否会更好地处理空值,但似乎可能会这样。

1 个答案:

答案 0 :(得分:0)

我担心问题中没有足够的信息可以肯定地回答(例如,您是否正在使用Microsoft.VisualStudio.PlatformUI库中的ObservableObject?ViewModelBase在哪里定义?)但我的猜测是ViewModelBase在调用PropertyChanged事件之前不会检查null,这将由SetProperty(ref currentViewModel, value)调用调用。

要解决此问题,我会:

a)确保ViewModelBase在调用PropertyChanged事件之前检查null,这通常按如下方式完成(取自ObservableObject代码):

protected void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
  PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
  if (propertyChanged == null)
    return;
  propertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

b)将初始视图模型分配给字段,而不是将不会导致触发属性更改事件的属性。因此构造函数应该是:

public MainWindowVM()
{
    NavCommand = new NavigationCommand<string>(OnNav);
    currentViewModel = masterViewVM; // Note lower case 'c' on currentViewModel
}

希望它有所帮助。