简体   繁体   English

将WPF窗口DataContext设置为RelativeSource Self

[英]Setting WPF Window DataContext to RelativeSource Self

If I set the Window's DataContext to this in the constructor as well as to {Binding RelativeSource={RelativeSource Self}} in XAML then I can see that the DataContext refers to the correct object instance (ie the MainWindow) by placing a break point in the code-behind's Loaded event. 如果我在构造函数中将Window的DataContext设置this以及在XAML 中将 {Binding RelativeSource={RelativeSource Self}}为I,那么我可以通过在其中放置一个断点来看到DataContext引用了正确的对象实例(即MainWindow)。代码隐藏的Loaded事件。 However, the Window's child element exampleButton's Command binding is null. 但是,Window的子元素exampleButton的Command绑定为null。 The assertion fails. 断言失败。

When I remove the XAML DataContext setting (and rely on the constructor setting only) then exampleButton's Command uses the DataContext correctly. 当我删除XAML DataContext设置(仅依赖于构造函数设置)时,exampleButton的Command会正确使用DataContext。

Why is exampleButton's Command bound to null in the XAML scenario? 为什么在XAML场景中exampleButton的Command绑定为null?

MainWindow.xaml 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 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
    }
}

Set ExampleCommand and DataContext before InitializeComponent : InitializeComponent之前设置ExampleCommandDataContext

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

Also note that there is no difference between using DataContext="{Binding RelativeSource={RelativeSource Self}}" or DataContext = this; 还要注意,使用DataContext="{Binding RelativeSource={RelativeSource Self}}"DataContext = this;没有区别DataContext = this; , if you set datacontext before initializecomponent. ,如果您在initializecomponent之前设置了datacontext。

Why is exampleButton's Command bound to null in the XAML scenario? 为什么在XAML场景中exampleButton的Command绑定为null?

Because the ExampleCommand property actually has a value of null by the time the InitializeComponent() method returns and the DataContext property is set. 因为ExampleCommand属性在InitializeComponent()方法返回并设置DataContext属性时实际上具有null值。

If you want to set a property to a new value after this, the class must implement the INotifyPropertyChanged interface for the target property to get refreshed automatically: 如果要在此之后将属性设置为新值,则该类必须实现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));
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM