2017-03-04 56 views
1

如果我在构造以及在XAML {Binding RelativeSource={RelativeSource Self}}设置窗口的DataContext到this话,我可以看到的DataContext是指正确的对象实例(即主窗口)通过将代码隐藏的Loaded事件中的一个断点。但是,Window的子元素exampleButton的Command绑定为null。断言失败。设置WPF窗口的DataContext到的RelativeSource自

当我删除XAML DataContext设置(并仅依赖于构造函数设置),则exampleButton的Command将正确使用DataContext。

为什么在XAML场景中将exampleButton的命令绑定为null?

MainWindow.xaml

<Window x:Class="MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="Example" 
     SizeToContent="WidthAndHeight" 
     x:Name="mainWindow" 
     DataContext="{Binding RelativeSource={RelativeSource Self}}" 
     Loaded="mainWindow_Loaded"> 
    <Button x:Name="exampleButton" Command="{Binding Path=ExampleCommand}" Content="Click"/> 
</Window> 

MainWindow.xaml.cs

public partial class MainWindow : Window 
{ 
    public ICommand ExampleCommand { get; } 

    public MainWindow() 
    { 
     InitializeComponent(); 
     DataContext = this; 
     ExampleCommand = new DelegateCommand(x => { throw new ApplicationException(); }); 
    } 

    private void mainWindow_Loaded(object sender, RoutedEventArgs e) 
    { 
     Debug.Assert(mainWindow == this); 
     Debug.Assert(mainWindow.DataContext == this); 
     Debug.Assert(exampleButton.DataContext == this); 
     Debug.Assert(exampleButton.Command == ExampleCommand); //<-- FAIL 
    } 
} 

回答

2

为什么在XAML场景中将exampleButton的命令绑定为null?

由于ExampleCommand属性实际上具有由时间InitializeComponent()方法返回空值和DataContext属性设置。

如果你想一个属性设置为在此之后一个新的值时,类必须实现INotifyPropertyChanged接口即可自动刷新目标属性:

public partial class MainWindow : Window, INotifyPropertyChanged 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     ExampleCommand = new RelayCommand<object>(x => { throw new ApplicationException(); }); 
    } 

    private ICommand _exampleCommand; 
    public ICommand ExampleCommand 
    { 
     get { return _exampleCommand; } 
     set { _exampleCommand = value; NotifyPropertyChanged(); } 
    } 

    private void mainWindow_Loaded(object sender, RoutedEventArgs e) 
    { 
     Debug.Assert(exampleButton.DataContext == this); 
     Debug.Assert(exampleButton.Command == ExampleCommand); //<-- FAIL 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 
+0

所以,这是因为:在XAML场景中,Window.DataContext * _is not_ * null,因此Button.Command * _is_ *绑定到ExampleCommand的空值(因为ExampleCommand尚未构造),但在代码后面场景,Window.DataContext * _is_ * null和Button.Command * _is not * _ bound,直到Window.DataContext被分配,然后分配ExampleCommand,然后它的工作原理*没有实现INotifyPropertyChanged? – Jono

+0

是的,这是正确的。 – mm8

+0

谢谢。如果我是诚实的,这很容易混淆。 – Jono

2

ExampleCommandDataContextInitializeComponent

DataContext = this; 
ExampleCommand = new DelegateCommand(x => { throw new ApplicationException(); }); 
InitializeComponent(); 

另外请注意,有使用没有什么区别10或DataContext = this;,如果在initializecomponent之前设置了datacontext。

+0

感谢@Ron,我还是有点对我的问题的确切答案不清楚,但你的回答突出了对InitializeComponent()的调用的重要性。 – Jono

+0

我很高兴能帮上忙。当然,我认为在你的情况下不需要一个'INotifyPropertyChanged',因为你要设置一次命令。请阅读[本文](http://stackoverflow.com/a/6531588/5615980)了解更多信息。 – Ron