无法获得内部 XAML 绑定以对抗依赖项 属性
Cannot get internal XAML binding to work against a Dependency Property
我有一个用户控件"CtrlComments",这个控件有以下XAML(超级基础)。
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:wpftoolkit="http://schemas.microsoft.com/wpf/2008/toolkit"
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"
x:Name="ucRoot">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="ID: " />
<TextBlock Text="{Binding Path=Deployment.Id}" />
</StackPanel>
</Grid>
背后的代码如下,它是让控件发挥作用的基础。关键是 DependencyObject typeof(DeploymentDto),它有一个名为 Id
的 int
属性,我们有兴趣根据上面的 XAML 绑定在我们的 window 上显示.
public partial class CtrlComments : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty DeploymentProperty =
DependencyProperty.Register("Deployment", typeof(DeploymentDto),
typeof(CtrlComments), new PropertyMetadata(new DeploymentDto()));
public DeploymentDto Deployment
{
get
{
return (DeploymentDto)GetValue(DeploymentProperty);
}
set
{
SetValue(DeploymentProperty, value);
OnPropertyChanged(new PropertyChangedEventArgs("Deployment"));
}
}
public CtrlComments()
{
InitializeComponent();
this.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
我们的问题是,尽管父控件和我的用户控件之间通过依赖项 属性 的绑定正在工作(已验证)并且 OnPropertyChanged
方法已触发,但 TextBlock
在我的 XAML 中没有更新。
我注意到,当 OnPropertyChanged
方法为 运行 时,事件处理程序为 null
,这意味着没有人收到 属性 更改的通知。
虽然我不明白为什么会这样。如果您能帮助解释我们哪里出了问题,我们将不胜感激。
谢谢!
我试图重现您的问题,在这样做的过程中,我认为我的问题出在 CtrlComments
中的以下行中:
this.DataContext = this;
删除这一行让它对我有用。另请注意(正如@Aron 在评论中所写)在 DependencyProperty
的 setter 中不应调用 INotifyPropertyChanged
的 OnPropertyChanged
。至少对我来说,根本没有必要实施 INPC。
在您使用 UserControl 的 XAML 文件中,您很可能会有另一个 DataContext
集(在更高级别上,可能在 Window
中),并且因此我想如果已经在其中设置(或覆盖),它不会继承给用户控件。下面是我的工作代码,但也许我误解了你在做什么。如果是这种情况,请扩展您的问题以包括您如何使用 UserControl,因为如果这不起作用,这是回答问题的关键:)
CtrlComments.xaml:
<UserControl x:Class="WpfApplication1.CtrlComments"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="ID: "/>
<TextBlock Text="{Binding Path=Deployment.Id}"/>
</StackPanel>
</Grid>
</UserControl>
CtrlComments.xaml.cs:
namespace WpfApplication1
{
public partial class CtrlComments : UserControl
{
public static readonly DependencyProperty DeploymentProperty =
DependencyProperty.Register("Deployment", typeof(DeploymentDto), typeof(CtrlComments), new PropertyMetadata(new DeploymentDto { Id = 5 }));
public DeploymentDto Deployment
{
get { return (DeploymentDto)GetValue(DeploymentProperty); }
set
{
SetValue(DeploymentProperty, value);
}
}
public CtrlComments()
{
InitializeComponent();
}
}
}
MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication1"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<StackPanel>
<local:CtrlComments x:Name="testUC" Height="100" Deployment="{Binding Deployment}"/>
<Button Click="Button_Click" Height="50" Width="100"/>
</StackPanel>
</Window>
MainWindow.xaml.cs:
namespace WpfApplication1
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
}
private DeploymentDto deployment = new DeploymentDto { Id = 2 };
public DeploymentDto Deployment
{
get { return deployment; }
set { deployment = value; OnPropertyChanged("Deployment"); }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Deployment = new DeploymentDto { Id = new Random().Next(100) };
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
}
部署到:
public class DeploymentDto
{
public int Id { get; set; }
}
将 MainWindow.DataContext
绑定到其代码隐藏非常丑陋,但由于它仅用于示例目的,我希望它没问题:)
我有一个用户控件"CtrlComments",这个控件有以下XAML(超级基础)。
<UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:wpftoolkit="http://schemas.microsoft.com/wpf/2008/toolkit"
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"
x:Name="ucRoot">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="ID: " />
<TextBlock Text="{Binding Path=Deployment.Id}" />
</StackPanel>
</Grid>
背后的代码如下,它是让控件发挥作用的基础。关键是 DependencyObject typeof(DeploymentDto),它有一个名为 Id
的 int
属性,我们有兴趣根据上面的 XAML 绑定在我们的 window 上显示.
public partial class CtrlComments : UserControl, INotifyPropertyChanged
{
public static readonly DependencyProperty DeploymentProperty =
DependencyProperty.Register("Deployment", typeof(DeploymentDto),
typeof(CtrlComments), new PropertyMetadata(new DeploymentDto()));
public DeploymentDto Deployment
{
get
{
return (DeploymentDto)GetValue(DeploymentProperty);
}
set
{
SetValue(DeploymentProperty, value);
OnPropertyChanged(new PropertyChangedEventArgs("Deployment"));
}
}
public CtrlComments()
{
InitializeComponent();
this.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (PropertyChanged != null)
PropertyChanged(this, e);
}
}
我们的问题是,尽管父控件和我的用户控件之间通过依赖项 属性 的绑定正在工作(已验证)并且 OnPropertyChanged
方法已触发,但 TextBlock
在我的 XAML 中没有更新。
我注意到,当 OnPropertyChanged
方法为 运行 时,事件处理程序为 null
,这意味着没有人收到 属性 更改的通知。
虽然我不明白为什么会这样。如果您能帮助解释我们哪里出了问题,我们将不胜感激。
谢谢!
我试图重现您的问题,在这样做的过程中,我认为我的问题出在 CtrlComments
中的以下行中:
this.DataContext = this;
删除这一行让它对我有用。另请注意(正如@Aron 在评论中所写)在 DependencyProperty
的 setter 中不应调用 INotifyPropertyChanged
的 OnPropertyChanged
。至少对我来说,根本没有必要实施 INPC。
在您使用 UserControl 的 XAML 文件中,您很可能会有另一个 DataContext
集(在更高级别上,可能在 Window
中),并且因此我想如果已经在其中设置(或覆盖),它不会继承给用户控件。下面是我的工作代码,但也许我误解了你在做什么。如果是这种情况,请扩展您的问题以包括您如何使用 UserControl,因为如果这不起作用,这是回答问题的关键:)
CtrlComments.xaml:
<UserControl x:Class="WpfApplication1.CtrlComments"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="ID: "/>
<TextBlock Text="{Binding Path=Deployment.Id}"/>
</StackPanel>
</Grid>
</UserControl>
CtrlComments.xaml.cs:
namespace WpfApplication1
{
public partial class CtrlComments : UserControl
{
public static readonly DependencyProperty DeploymentProperty =
DependencyProperty.Register("Deployment", typeof(DeploymentDto), typeof(CtrlComments), new PropertyMetadata(new DeploymentDto { Id = 5 }));
public DeploymentDto Deployment
{
get { return (DeploymentDto)GetValue(DeploymentProperty); }
set
{
SetValue(DeploymentProperty, value);
}
}
public CtrlComments()
{
InitializeComponent();
}
}
}
MainWindow.xaml:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplication1"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
<StackPanel>
<local:CtrlComments x:Name="testUC" Height="100" Deployment="{Binding Deployment}"/>
<Button Click="Button_Click" Height="50" Width="100"/>
</StackPanel>
</Window>
MainWindow.xaml.cs:
namespace WpfApplication1
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
}
private DeploymentDto deployment = new DeploymentDto { Id = 2 };
public DeploymentDto Deployment
{
get { return deployment; }
set { deployment = value; OnPropertyChanged("Deployment"); }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Deployment = new DeploymentDto { Id = new Random().Next(100) };
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
}
部署到:
public class DeploymentDto
{
public int Id { get; set; }
}
将 MainWindow.DataContext
绑定到其代码隐藏非常丑陋,但由于它仅用于示例目的,我希望它没问题:)