WPF UserControl doesn't inherit parent DataContext
我正在尝试开发可重用的UserControl,但是遇到绑定问题。 我创建了一个较小的应用程序来对其进行测试,但无法对其进行整理,或者至少了解了为什么它无法按我的预期工作。
代码如下。 我所期望的是我放在MainWindow.xaml上的TestUserControl实例将继承那里的DataContext,就像它的TextBlock一样。 相反,它的DataContext似乎为null。 DataContext没有传递下去是有原因的吗? 是否需要自动设置?
MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | <Window x:Class="WpfTestApp.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:WpfTestApp" mc:Ignorable="d" Title="MainWindow" Height="350" Width="525"> <StackPanel Orientation="Vertical"> <local:TestUserControl TextFromParent="{Binding SomeText}" /> <TextBlock Name="TestTextBlock" Text="{Binding SomeText}" /> </StackPanel> </Window> |
MainWindow.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | using System.ComponentModel; using System.Runtime.CompilerServices; using System.Windows; namespace WpfTestApp { public partial class MainWindow : Window, INotifyPropertyChanged { private string _someText; public MainWindow() { DataContext = this; InitializeComponent(); SomeText ="New Text!"; } public string SomeText { get { return _someText; } set { _someText = value; NotifyOnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyOnPropertyChanged([CallerMemberName] string propertyName ="") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } } |
TestUserControl.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 | <UserControl x:Class="WpfTestApp.TestUserControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:WpfTestApp" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <TextBlock Name="TheTextBlock" Text="{Binding TextFromParent}" /> </Grid> </UserControl> |
TestUserControl.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using System.Windows; using System.Windows.Controls; namespace WpfTestApp { public partial class TestUserControl : UserControl { public TestUserControl() { InitializeComponent(); } public string TextFromParent { get { return (string)GetValue(TextFromParentProperty); } set { SetValue(TextFromParentProperty, value); } } public static readonly DependencyProperty TextFromParentProperty = DependencyProperty.Register( "TextFromParent", typeof(string), typeof(TestUserControl), new PropertyMetadata()); } } |
程序在运行时如下所示,第一个文本为空白,然后是具有有效绑定的TextBlock:
UserControl实际上是从其父元素继承DataContext的。 但是,该DataContext中没有
UserControl的XAML中的Binding应该绑定到UserControl本身的属性,而不是当前DataContext之一。 因此,它必须使用UserControl实例作为源对象:
1 2 | <TextBlock Text="{Binding TextFromParent, RelativeSource={RelativeSource AncestorType=UserControl}}" /> |
不能将UserControl的DataContext设置为其自身,因为这样可以防止从控件的父元素继承DataContext值。
但是,您可以在UserControl的XAML中设置根元素的DataContext,以避免在可能的许多绑定上设置RelativeSource:
1 2 3 4 5 | <UserControl ...> <Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}"> <TextBlock Text="{Binding TextFromParent}" /> </Grid> </UserControl> |
试试看,您不需要在绑定中使用任何RelativeSource:
1 2 3 4 | <Grid Name="GrdContent"> <TextBlock Name="TheTextBlock" Text="{Binding TextFromParent}" /> </Grid> |
...
1 2 3 4 5 6 7 8 | public MainWindow() { GrdContent.DataContext = this; InitializeComponent(); SomeText ="New Text!"; } |