[英]DataContext on CommandParameter differs from DataContext on Command itself
This question is related to my previous question here: Predicate won't validate parameter correctly 这个问题与我之前的问题有关: Predicate不会正确验证参数
At first some information on my Models: 首先是关于我的模型的一些信息:
BaseViewModel: 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". 正如你在BaseViewModel中看到的那样,属性“Name”和“HomePage”在同一个类中定义,因此如果DataContext是一个派生自“BaseViewModel”的ViewModel,它们应该是可访问的。 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. 起初我失去了理智,因为似乎没有任何工作 - 输出窗口表示无法检索“HomePage”的值 - 除了每次都正确绑定的Name。
After I nearly gave up I named my View "Test" and tried to redirect the CommandProperty binding along an ElementName - and it worked: 在我几乎放弃之后,我命名了我的View“Test”并试图沿着ElementName重定向CommandProperty绑定 - 它工作正常:
<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? 为什么在Name属性之间区分DataContext而不分配ElementName和HomePage需要ElementName?
Update 1: 更新1:
MainViewModel : BaseViewModel 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: 更新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: 更新3:
Now it's getting really strange - I tried to add an TextBlock and bind it directly to HomePage.Text - and it works. 现在它变得非常奇怪 - 我试图添加一个TextBlock并将其直接绑定到HomePage.Text - 它的工作原理。
<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? 那么为什么我不能直接访问HomePage绑定到CommandParameter但将TextBlock的Text属性直接绑定到HomePage.Name有效?
Update 4: 更新4:
The Output Windows sais: 输出Windows sais:
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; System.Windows.Data信息:10:无法使用绑定检索值,并且不存在有效的回退值; using default instead. 使用默认值。 BindingExpression:Path=Name; BindingExpression:路径=名称; DataItem=null; 的DataItem = NULL; target element is 'Button' (Name=''); target元素是'Button'(Name =''); target property is 'Content' (type 'Object') target属性是'Content'(类型'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; System.Windows.Data信息:10:无法使用绑定检索值,并且不存在有效的回退值; using default instead. 使用默认值。 BindingExpression:Path=DataContext.ChangePageCommand; BindingExpression:路径= DataContext.ChangePageCommand; DataItem=null; 的DataItem = NULL; target element is 'Button' (Name=''); target元素是'Button'(Name =''); target property is 'Command' (type 'ICommand') target属性是'Command'(类型'ICommand')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; System.Windows.Data信息:10:无法使用绑定检索值,并且不存在有效的回退值; using default instead. 使用默认值。 BindingExpression:Path=HomePage; BindingExpression:路径=首页; DataItem=null; 的DataItem = NULL; target element is 'Button' (Name=''); target元素是'Button'(Name =''); target property is 'CommandParameter' (type 'Object') target属性是'CommandParameter'(类型'Object')
System.Windows.Data Information: 10 : Cannot retrieve value using the binding and no valid fallback value exists; System.Windows.Data信息:10:无法使用绑定检索值,并且不存在有效的回退值; using default instead. 使用默认值。 BindingExpression:Path=HomePage.Name; BindingExpression:路径= HomePage.Name; DataItem=null; 的DataItem = NULL; target element is 'TextBlock' (Name=''); target元素是'TextBlock'(Name =''); target property is 'Text' (type 'String') target属性是'Text'(类型'String')
But everything except the CommandParameter gets bound successfully. 但是除CommandParameter之外的所有内容都会成功绑定。 Is it possible that the CommandParameter (and the underlaying CanExecute-Method) won't get re-validated once the binding is refreshed? 修复绑定后,CommandParameter(和底层的CanExecute-Method)是否可能无法重新验证? Maybe the binding fails at first but every binding except the CommandParameter gets refreshed and revalidated. 也许最初绑定失败但除了CommandParameter之外的每个绑定都会刷新并重新生成。 But how could I solve this issue? 但是我怎么能解决这个问题呢?
I'm proud to announce that I've solved this silly problem: 我很自豪地宣布我已经解决了这个愚蠢的问题:
I assume that the RelativeSource I'm using to redirect my CommandBinding to the Window's ViewModel breaks the DataContext of all following Properties (!Not Controls). 我假设我用来将我的CommandBinding重定向到Window的ViewModel的RelativeSource打破了以下所有属性的DataContext(!Not Controls)。
Not working: 不工作:
<Button Grid.Row="0"
Grid.Column="0"
Height="50"
Content="{Binding PreviousPageViewModel.Name}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding PreviousPageViewModel}" />
Working: 工作:
<Button Grid.Row="0"
Grid.Column="0"
Height="50"
Content="{Binding PreviousPageViewModel.Name}"
CommandParameter="{Binding PreviousPageViewModel}"
Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>
So in this case the order of Properties is important. 所以在这种情况下,属性的顺序很重要。
Note: The DataContext for all following Controls is correct. 注意:所有后续控件的DataContext都是正确的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.