CommandParameter上的DataContext与Command本身上的DataContext不同

时间:2016-04-13 05:13:47

标签: c# wpf xaml datacontext icommand

此问题与我之前提出的问题有关:Predicate won't validate parameter correctly

首先我的模特的一些信息:

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));
        }
    }
}

问题:

<Button Content="{Binding Name}" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
        CommandParameter="{Binding HomePage}"/>

正如您在BaseViewModel中看到的那样,属性&#34;名称&#34;和#34;主页&#34;如果DataContext是一个派生自&#34; BaseViewModel&#34;的ViewModel,则它们在同一个类中定义,因此它们应该是可访问的。 起初我失去了理智,因为似乎没有任何工作 - 输出窗口说的是&#34; HomePage&#34;无法检索 - 其他名称每次都被正确绑定。

在我几乎放弃之后,我将我的观点命名为&#34;测试&#34;并试图沿着ElementName重定向CommandProperty绑定 - 它工作正常:

<Button Content="{Binding Name}" Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"
        CommandParameter="{Binding DataContext.HomePage, ElementName=Test}"/>

但为什么呢?为什么在Name属性之间区分DataContext而不分配ElementName和HomePage需要ElementName?

更新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;
    }

更新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}"/>

更新3:

现在它变得非常奇怪 - 我尝试添加一个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}"/>

那么为什么我不能在绑定到CommandParameter时直接访问HomePage,而是直接将TextBlock的Text属性绑定到HomePage.Name有效?

更新4:

输出Windows sais:

System.Windows.Data信息:10:无法使用绑定检索值,并且不存在有效的回退值;使用默认值。 BindingExpression:路径=名称;的DataItem = NULL;目标元素是&#39;按钮&#39; (名称=&#39;&#39);目标属性是&#39;内容&#39; (键入&#39;对象&#39;)

System.Windows.Data信息:10:无法使用绑定检索值,并且不存在有效的回退值;使用默认值。 BindingExpression:路径= DataContext.ChangePageCommand;的DataItem = NULL;目标 元素是&#39; Button&#39; (名称=&#39;&#39);目标财产是&#39; Command&#39; (键入&#39; ICommand&#39;)

System.Windows.Data信息:10:无法使用绑定检索值,并且不存在有效的回退值;使用默认值。 BindingExpression:路径=首页;的DataItem = NULL;目标元素是&#39;按钮&#39; (名称=&#39;&#39);目标属性是&#39; CommandParameter&#39; (键入&#39;对象&#39;)

System.Windows.Data信息:10:无法使用绑定检索值,并且不存在有效的回退值;使用默认值。 BindingExpression:路径= HomePage.Name;的DataItem = NULL;目标元素是&#39; TextBlock&#39; (名称=&#39;&#39);目标属性是&#39; Text&#39; (键入&#39; String&#39;)

但除CommandParameter之外的所有内容都会成功绑定。修订绑定后,CommandParameter(和底层的CanExecute-Method)是否可能无法重新验证?也许最初绑定失败但除了CommandParameter之外的每个绑定都会刷新并重新生成。但是我怎么能解决这个问题呢?

1 个答案:

答案 0 :(得分:1)

我很自豪地宣布我已经解决了这个愚蠢的问题:

我假设我用来将我的CommandBinding重定向到Window的ViewModel的RelativeSource打破了以下所有属性的DataContext(!Not Controls)。

不工作:

<Button Grid.Row="0" 
            Grid.Column="0" 
            Height="50" 
            Content="{Binding PreviousPageViewModel.Name}"
            Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType=Window}}"
            CommandParameter="{Binding PreviousPageViewModel}" />

工作:

<Button Grid.Row="0" 
            Grid.Column="0" 
            Height="50" 
            Content="{Binding PreviousPageViewModel.Name}" 
            CommandParameter="{Binding PreviousPageViewModel}" 
            Command="{Binding DataContext.ChangePageCommand, RelativeSource={RelativeSource AncestorType=Window}}"/>

因此,在这种情况下,属性的顺序很重要。

注意:所有后续控件的DataContext都是正确的。