C# 将WPF窗口DataContext设置为RelativeSource Self
如果我在构造函数中将窗口的DataContext设置为C# 将WPF窗口DataContext设置为RelativeSource Self,c#,wpf,xaml,C#,Wpf,Xaml,如果我在构造函数中将窗口的DataContext设置为this,并在XAML中将其设置为{Binding RelativeSource={RelativeSource Self}},那么通过在代码隐藏的加载事件中放置断点,我可以看到DataContext引用了正确的对象实例(即主窗口)。但是,窗口的子元素exampleButton的命令绑定为null。断言失败了 当我删除XAML DataContext设置(并且仅依赖构造函数设置)时,exampleButton的命令将正确使用DataConte
this
,并在XAML中将其设置为{Binding RelativeSource={RelativeSource Self}}
,那么通过在代码隐藏的加载事件中放置断点,我可以看到DataContext引用了正确的对象实例(即主窗口)。但是,窗口的子元素exampleButton的命令绑定为null。断言失败了
当我删除XAML DataContext设置(并且仅依赖构造函数设置)时,exampleButton的命令将正确使用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
}
}
公共部分类主窗口:窗口
{
公共ICommand示例命令{get;}
公共主窗口()
{
初始化组件();
DataContext=this;
ExampleCommand=newdelegateCommand(x=>{throw new ApplicationException();});
}
已加载私有void主窗口(对象发送器、路由目标)
{
Assert(mainWindow==this);
Assert(mainWindow.DataContext==this);
Assert(exampleButton.DataContext==this);
Debug.Assert(exampleButton.Command==ExampleCommand);///p>在初始化组件之前设置ExampleCommand
和DataContext
:
DataContext = this;
ExampleCommand = new DelegateCommand(x => { throw new ApplicationException(); });
InitializeComponent();
还请注意,如果在初始化组件之前设置DataContext=“{Binding RelativeSource={RelativeSource Self}}”
或DataContext=this;
,则使用DataContext=“{Binding RelativeSource={RelativeSource Self}}”之间没有区别
为什么在XAML场景中exampleButton的命令绑定为null
因为ExampleCommand
属性在InitializeComponent()
方法返回并设置DataContext
属性时实际具有null值
如果要在此之后将属性设置为新值,则类必须实现目标属性的接口以自动刷新:
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));
}
}
public分部类主窗口:窗口,INotifyPropertyChanged
{
公共主窗口()
{
初始化组件();
ExampleCommand=newrelayCommand(x=>{throw new ApplicationException();});
}
专用ICommand_示例命令;
公共ICommand example命令
{
获取{return\u exampleCommand;}
设置{u exampleCommand=value;NotifyPropertyChanged();}
}
已加载私有void主窗口(对象发送器、路由目标)
{
Assert(exampleButton.DataContext==this);
Debug.Assert(exampleButton.Command==ExampleCommand);//这是因为:在XAML场景中,Window.DataContext\u不是空的,所以Button.Command\u绑定到ExampleCommand的空值(因为ExampleCommand还没有被构造),但在代码隐藏场景中,Window.DataContext\u是空的,因此按钮。命令\u在Window.DataContext被分配之后才被绑定,然后ExampleCommand被分配,然后它就可以工作,而不实现INotifyPropertyChanged?谢谢。老实说,这很让人困惑。谢谢@Ron,我仍然不太清楚它的确切答案我的问题,但您的回答强调了调用InitializeComponent()的重要性。我很高兴能提供帮助。当然,我认为在您的情况下不需要使用INotifyPropertyChanged
,因为您要设置一次命令。有关详细信息,请阅读。