0

Again, I'm confused about visibility or accessibility of WPF viewmodels.
I'm still at the beginning of my learning-curve, so please be patient with me ^^

My App is a main window with a menu-bar (Ribbon) and two child usercontrols, that are loaded with their own viewmodel.
One child contains a settingsVM and the other child contains a projectVM.

This is the Resource of the two children and their content-control:

<Window.Resources>
    <viewmodels:MainViewModel x:Key="MainVM" />
    <DataTemplate x:Name="settingsViewTemplate" DataType="{x:Type viewmodels:SettingsViewModel}">
        <views:SettingsView DataContext="{Binding SettingsVM, Source={StaticResource MainVM}}"/>
    </DataTemplate>
    <DataTemplate x:Name="projectsViewTemplate" DataType="{x:Type viewmodels:ProjectViewModel}">
        <views:ProjectView DataContext="{Binding ProjectVM, Source={StaticResource MainVM}}"/>
    </DataTemplate>
</Window.Resources>

<!--.... a lot of menu stuff-->

<ContentControl Content="{Binding SelectedViewModel, Source={StaticResource MainVM}}"/>

The correspponding Main Viewmodel:

namespace MyApp.ViewModels
{
  public class MainViewModel : BaseViewModel
  {
    //The BaseViewModel contains only the PropertyChanged-event.
    #region Private Properties
    private BaseViewModel _selectedViewModel;
    #endregion

    #region Public Properties
    public ProjectViewModel ProjectVM { get; set; }
    public SettingsViewModel SettingsVM { get; set; }
    public BaseViewModel SelectedViewModel {
        //This controls, which child is shown
        get { return _selectedViewModel; }
        set
        {
            _selectedViewModel = value;
            OnPropertyChanged("SelectedViewModel");
        }
    }
    #endregion

    #region Constructor
    public MainViewModel()
    {
        this.SettingsVM = new SettingsViewModel(this);
        this.ProjectVM = new ProjectViewModel(this) { Settings = SettingsVM };
        SelectedViewModel = SettingsVM;
    }
    #endregion
  }
}

Now I wanted to show a property of the SettingsVM inside the ribbonMenu. How can I access a property of the SettingsVM from the MainVM?

I tried several approaches like the following:

<TextBox Text="{Binding SettingsVM.Masterfile, Mode=OneWay}" />

or

<TextBox Text="{Binding MainVM.SettingsVM.Masterfile, Mode=OneWay}" />

but everything is empty. So can please someone explain to me, what the MainVM contains and how I could access it, or better its SettingsVM child? I thought I understood that but it seems not.

Thanks Carsten

EDIT

A piece of the mainwindow:

<ribbon:RibbonWindow
x:Class="PlcGenerator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ribbon="clr-namespace:System.Windows.Controls.Ribbon;assembly=System.Windows.Controls.Ribbon"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:MyApp"
xmlns:controls="clr-namespace:MyApp.Views.Controls"
xmlns:misc="clr-namespace:MyApp.Misc"
xmlns:viewmodels="clr-namespace:MyApp.ViewModels"
xmlns:views="clr-namespace:MyApp.Views"
mc:Ignorable="d"
Closing="ClosingApp"
Title="My App" Height="700" Width="1200">


<Window.Resources>
    <DataTemplate x:Name="settingsViewTemplate" DataType="{x:Type viewmodels:SettingsViewModel}">
        <views:SettingsView DataContext="{Binding SettingsVM}"/>
    </DataTemplate>
    <DataTemplate x:Name="projectsViewTemplate" DataType="{x:Type viewmodels:ProjectViewModel}">
        <views:ProjectView DataContext="{Binding ProjectVM}"/>
    </DataTemplate>
</Window.Resources>


<DockPanel LastChildFill="True">
    
    <ribbon:Ribbon DockPanel.Dock="Top">
        <Ribbon.QuickAccessToolBar>
            <RibbonQuickAccessToolBar>
                <RibbonButton Label="Speichern" SmallImageSource="Icons/saveHS.png"/>
                
            </RibbonQuickAccessToolBar>
        </Ribbon.QuickAccessToolBar>

        <Ribbon.ApplicationMenu>
            <RibbonApplicationMenu SmallImageSource="Icons/ApplicationMenu.png">

                <RibbonApplicationMenuItem Header="Neues Projekt" ImageSource="Icons/32x32/Add_32x32.png" Command="{Binding ProjectVM.NewProject}" />
                <RibbonApplicationMenuItem Header="Projekt öffnen" ImageSource="Icons/32x32/Scan_32x32.png" Command="{Binding ProjectVM.OpenProject}" />
                <RibbonApplicationMenuItem Header="Projekt speichern" ImageSource="Icons/32x32/Save_32x32.png" Command="{Binding ProjectVM.SaveProject}" />
                <RibbonApplicationMenuItem Header="Beenden" ImageSource="Icons/32x32/Exit_32x32.png" Click="MnuExitClick" />
                <RibbonApplicationMenu.FooterPaneContent>
                    <RibbonButton Click="MnuExitClick" Label="Exit" SmallImageSource="Icons/32x32/Exit_32x32.png" HorizontalAlignment="Right"/>
                </RibbonApplicationMenu.FooterPaneContent>
           
            </RibbonApplicationMenu>
        </Ribbon.ApplicationMenu>

        <Ribbon.HelpPaneContent>
            <RibbonButton Content="Hilfe" SmallImageSource="Icons/32x32/Help_32x32.png"/>
        </Ribbon.HelpPaneContent>
        
        <!-- Start -->
        <RibbonTab x:Name="StartTab" Header="Start" >
            <RibbonGroup Header="Projekt">
                <RibbonButton Label="Projekt" Command="{Binding ProjectVM.ShowProject}" LargeImageSource="/Icons/32x32/ColorLayers_32x32.png" />
                <RibbonButton Label="Neues Projekt" SmallImageSource="Icons/32x32/Add_32x32.png" Command="{Binding ProjectVM.NewProject}"/>
                <RibbonButton Label="Projekt öffnen" SmallImageSource="Icons/32x32/Scan_32x32.png" Command="{Binding ProjectVM.OpenProject}"/>
                <RibbonButton Label="Speichern" SmallImageSource="Icons/32x32/Save_32x32.png" Command="{Binding ProjectVM.SaveProject}"/>


<TextBox Text="{Binding SettingsVM.MasterFile, Mode=OneWay}" />


            </RibbonGroup>


    </ribbon:Ribbon>

        <!-- Fensterinhalt-->
    <ContentControl Content="{Binding SelectedViewModel}"/>
    <!--</Grid>-->
</DockPanel>

</ribbon:RibbonWindow>

Second Edit

Actually, I have no value inside the controls so I think the viewmodels are null...?
I removed all , Source={StaticResource MainVM} (above) and
<viewmodels:MainViewModel x:Key="MainVM" /> from Windows.Resources, as mentioned.

In <TextBox Text="{Binding SettingsVM.MasterFile, Mode=OneWay}" /> (nested inside the Ribbon-menu), I get a value so SettingsVMshould be loaded correctly.

SelectedViewModel should contain the selected viewmodel (including its Control), as the Control switches, when I change between ProjectVM and SettingsVM. I also could switch manually by Inserting <ContentControl Content="{Binding SettingsVM}"/> or <ContentControl Content="{Binding ProjectVM}"/>.

Mainviewmodel is initialized, the constructor is hit on startup.

Solved!

Thanks to @XAMlMAX and this explanation: WPF MVVM navigate views

My last fault was the wrong resource-declaration. I changed it to:

<Window.Resources>
    <DataTemplate DataType="{x:Type viewmodels:SettingsViewModel}">
        <views:SettingsView />
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewmodels:ProjectViewModel}">
        <views:ProjectView />
    </DataTemplate>
</Window.Resources>

Now everything works as expected :)

Telefisch
  • 305
  • 1
  • 19
  • 1
    It's usually wrong to explicitly set the DataContext of an element in a DataTemplate. The DataContext is supposed to be passed by property value inheritance from the ContentControl or ContentPresenter that applies the DataTemplate. – Clemens Oct 29 '20 at 10:50
  • An exception might be when you want to set the element's DataContext to a property of the object in the ContentControl's DataContext, like `` – Clemens Oct 29 '20 at 10:52
  • 1
    Firstly set up data context of your main window like this so you don't have to reference {Source={StaticResource MainVM}} and remove MainVM from resources. For some reason you have names on Data templates, delete them. Could you show us xaml that you use for menu, I have a suspicion you are setting data context somewhere where you shouldn't. – XAMlMAX Oct 29 '20 at 11:07
  • Ok, I'm afraid I didn't understand that concept. I thought of that like forms (controls including their datamodels) and I have to define a DataTemplate for each "form". And at the end I show one of the "forms". Perhaps it's neccessary to know, that settings and projects are completely devided from eachother. The settings are the app-settings, like template-folders etc., since the projectVM could be every project independent from the settings. So I load the settingsVM on startup and when a project is loaded, I transfer the settings as a parameter in the projectVMs Consturctor. – Telefisch Oct 29 '20 at 11:09
  • I updated my question with MainWindow.xaml... – Telefisch Oct 29 '20 at 11:17
  • @XAMlMAX tried to do it as you supposed... Now, the commands still work and I can show an information of a child VM in the Menubar but now the controls have no content. I can switch between them them but have no values inside them. `` should be the rigth approach? – Telefisch Oct 29 '20 at 11:39
  • 1
    If you set data context like I told you to, then remove `, Source={StaticResource MainVM}` from your bindings. Also look into Output window and look for errors there, that's where you will find how your bindings fail. – XAMlMAX Oct 29 '20 at 14:01

0 Answers0