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 SettingsVM
should 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 :)