在DependencyProperty setter中更新UserControl子组件不工作

本文关键字:组件 工作 UserControl 更新 DependencyProperty setter | 更新日期: 2023-09-27 18:10:36

我在Silverlight应用程序中有一个UserControl,由于某种原因,如果我将UserControl绑定到视图模型中的值,则UserControl的DependencyProperty没有设置。我花了几个小时以试错的方式调试,现在我完全不知道下一步要尝试什么。

我可以用

在新的Silverlight项目中重现这个问题

MainPage.xaml

<UserControl x:Class="SilverlightApplication1.MainPage"
    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:SilverlightApplication1"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
        <StackPanel>
            <local:MyCtrl HeaderText="{Binding HeaderText}"/>
            <TextBlock Text="{Binding HeaderText}"/>
        </StackPanel>
    </Grid>
</UserControl>

MainPage.xaml.cs

using System.Windows.Controls;
namespace SilverlightApplication1
{
    public class Vm
    {
        public string HeaderText 
        { get; set; }
    }
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            DataContext = new Vm() { HeaderText = "My Header" };
        }
    }
}

MyCtrl。xaml(作为新的"Silverlight用户控件"添加)

<UserControl x:Class="SilverlightApplication1.MyCtrl"
    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"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">
    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock x:Name="txtHeader" />
    </Grid>
</UserControl>

MyCtrl.xaml.cs

using System.Windows;
using System.Windows.Controls;
namespace SilverlightApplication1
{
    public partial class MyCtrl : UserControl
    {
        public MyCtrl()
        {
            InitializeComponent();
        }
        public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
            "HeaderText", typeof(string), typeof(MyCtrl), null);
        public string HeaderText
        {
            get { return (string)GetValue(HeaderTextProperty); }
            set
            {
                // NEVER CALLED
                SetValue(HeaderTextProperty, value);
                this.txtHeader.Text = value;
            }
        }
    }
}

项目的其余部分使用"原样",即没有更改编译器选项,服务器部分也保留"原样"。

观察:

  • 我看到Vm.HeaderText的getter在绑定期间被调用操作,但DependencyProperty MyCtrl.HeaderText的setter永远不会被调用。
  • MainPage中自定义控件下方的TextBlock正确显示绑定值。
  • 没有编译警告。
  • 没有抛出异常。
  • 应用程序运行时没有调试输出。

这感觉就像一些重要的东西在它不应该的地方无声地失败了。

在DependencyProperty setter中更新UserControl子组件不工作

也许我可以对你的观察和假设提供一些启发:

  • 可以更新DependencyProperty setter中的子控件。调用setter并亲自查看,更新将被执行。您错误地认为绑定引擎必须调用setter。嗯,它只调用控件的SetValue(HeaderTextProperty, newValue);,不需要调用setter。

  • 你的观察是指定行为

  • 正如你所发现的,正确的方法是使用propertyChanged回调。

  • 视图模型Vm.HeaderText上的属性getter由绑定引擎调用,因为视图模型没有DependencyObject, HeaderText没有DependencyProperty,所以没有SetValue(...)GetValue(...)

  • 您看不到任何编译器警告或异常,也没有任何静默失败,因为您的场景没有任何问题。

嗯,似乎你不能更新一个DependencyProperty setter内的子控件(将是有趣的知道为什么,如果这是指定的行为…)

public static readonly DependencyProperty HeaderTextProperty = DependencyProperty.Register(
    "HeaderText", typeof(string), typeof(MyCtrl), new PropertyMetaData(OnHeaderTextChanged));
public string HeaderText
{
    get { return (string)GetValue(HeaderTextProperty); }
    set { SetValue(HeaderTextProperty, value); }
}
private static void OnHeaderTextChanged(DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
    var ctrl = d as MyCtrl;
    ctrl.txtHeader.Text = (string)e.NewValue;
}