2017-03-04 31 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