This question is related to my previous question here: Predicate won't validate parameter correctly
At first some information on my Models:
BaseViewModel:
public abstract class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _name;
public string Name
{
get
{
return _name;
}
set
{
if (Name != value)
{
_name = value;
OnPropertyChanged("Name");
}
}
}
private BaseViewModel _homePage;
public BaseViewModel HomePage
{
get
{
return _homePage;
}
set
{
if (HomePage != value)
{
_homePage = value;
OnPropertyChanged("HomePage");
}
}
}
public void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler temp = PropertyChanged;
if (temp != null)
{
temp(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Problem:
<Button Content="{Binding Name}" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding HomePage}"/>
As you can see in the BaseViewModel, the Properties "Name" and "HomePage" are defined in the same class so they should be accessible if the DataContext is a ViewModel which derives from "BaseViewModel". At first I lost my mind because nothing seemed to work - the output window said that the value of "HomePage" could not be retrieved - other that the Name which got bound properly every time.
After I nearly gave up I named my View "Test" and tried to redirect the CommandProperty binding along an ElementName - and it worked:
<Button Content="{Binding Name}" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding DataContext.HomePage, ElementName=Test}"/>
But why? Why differs the DataContext between the Name Property which could be bound without assigning an ElementName and HomePage which requires the ElementName?
Update 1:
MainViewModel : BaseViewModel
private RelayCommand _command;
public RelayCommand ChangePageCommand {
get {
return _command ?? (_command = new RelayCommand(p => ChangeViewModel((BaseViewModel)p), x => {
return x is BaseViewModel;
}));
}
}
public void ChangeViewModel(BaseViewModel viewModel) {
CurrentPageViewModel = viewModel;
}
Update 2:
<Window.Resources>
<DataTemplate DataType="{x:Type home:HomeViewModel}">
<home:Home/>
</DataTemplate>
<DataTemplate DataType="{x:Type ua:UserAdministrationViewModel}">
<ua:UserAdministration/>
</DataTemplate>
</Window.Resources>
<ContentControl Content="{Binding CurrentPageViewModel}"/>
Update 3:
Now it's getting really strange - I tried to add an TextBlock and bind it directly to HomePage.Text - and it works.
<Button Height="50" Content="{Binding Name}" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
CommandParameter="{Binding DataContext.HomePage, ElementName=Test}"/>
<TextBlock Text="{Binding HomePage.Name}"/>
So why can't I directly access HomePage when binding to the CommandParameter but binding a TextBlock's Text Property directly to HomePage.Name works?
Update 4:
The Output Windows sais:
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=Name; DataItem=null; target element is 'Button' (Name=''); target property is 'Content' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=DataContext.ChangePageCommand; DataItem=null; target element is 'Button' (Name=''); target property is 'Command' (type 'ICommand')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=HomePage; DataItem=null; target element is 'Button' (Name=''); target property is 'CommandParameter' (type 'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; using default instead. BindingExpression:Path=HomePage.Name; DataItem=null; target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')
But everything except the CommandParameter gets bound successfully. Is it possible that the CommandParameter (and the underlaying CanExecute-Method) won't get re-validated once the binding is refreshed? Maybe the binding fails at first but every binding except the CommandParameter gets refreshed and revalidated. But how could I solve this issue?