关于用户控件中DependencyProperty的setter中代码的问题

Questions about codes in the setter of a DependencyProperty in a user control

我正在页面上显示 time/clock 作为用户控件 (ClockControl),实际时间模型由另一个 [=96] 的 DateTime 对象驱动=] (ClockTime)。我在 ClockControl:

上有 2 个文本块
  1. Textblock 'Second_update_by_binding' 绑定到依赖项 属性 'Second_binded',后者又绑定到模型 ClockTime 'Second'.

  2. Textblock 'Second_update_by_manipulating' 通过操纵模型 ClockTime 'Second' 的值进行更新,以便在 'Second' 仅为 1 时在前面添加“0”数字(或小于 10)

我设法实现了我想要的,不管它是否是最好的方法。但是,我遇到了一些我不太明白为什么会发生的问题。特别是,我最困惑的是时钟用户控件中 getter/setter 依赖项 属性 中代码背后的逻辑。

MainPage.xaml:

<Page x:Class="App1.MainPage" ...">
    <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
        <local:ClockControl x:Name="useControl" 
               Second_binded="{Binding Second}" 
               Second_manipulated="{Binding Second}"  />
    </Grid>
</Page>

MainPage.cs:

public sealed partial class MainPage : Page
{
    ClockTime clock;
    DispatcherTimer Timer;

    public MainPage()
    {
        clock = new ClockTime();
        this.InitializeComponent();
        this.DataContext = clock;
          // I am adding this DispatchTimer to force the update of the text 
          // 'Second_update_by_manipulating' on the ClockControl since the
          // Binding of Second_manipulated doesnt work
        Timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 1) };
        Timer.Tick += Timer_Tick;
        Timer.Start();
    }

    private void Timer_Tick(object sender, object e)
    {
        useControl.Second_manipulated = clock.Second.ToString();
    }
}

时钟时间模型:

class ClockTime : INotifyPropertyChanged
{
    public ClockTime()
    {
        var Timer = new DispatcherTimer { Interval = new TimeSpan(0, 0, 1) };
        Timer.Tick += Timer_Tick;
        Timer.Start();
    }

    private void Timer_Tick(object sender, object e)
    {
        Second = DateTime.Now.Second;
    }

    //===================================================
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String info)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
    }
    //===================================================
    private int _second;
    public int Second
    {
        get { return this._second; }
        set
        {
            if (value != this._second)
            {
                this._second = value;
                NotifyPropertyChanged("Second");
            }
        }
    }
}

ClockControl.xaml:

<UserControl x:Class="App1.ClockControl" ...>
    <Grid>
        <StackPanel>
            <TextBlock x:Name="Second_update_by_manipulating"  />
            <TextBlock x:Name="Second_update_by_binding" Text="{Binding Second_binded}" />
        </StackPanel>
    </Grid>
</UserControl>

ClockControl.cs:

public sealed partial class ClockControl : UserControl
{
    public ClockControl()
    {
        this.InitializeComponent();
        (this.Content as FrameworkElement).DataContext = this;
    }
    //==================================
    public String Second_binded
    {
        get {
            return (String)GetValue(Second_bindedProperty); 
        }
        set {
            Debug.WriteLine(" in Second_binded ");
            SetValue(Second_bindedProperty, value);
        }
    }
    public static readonly DependencyProperty Second_bindedProperty =
        DependencyProperty.Register(
        "Second_binded", 
        typeof(string),
        typeof(ClockControl), 
        new PropertyMetadata(""));
    //==================================
    public String Second_manipulated
    {
        get
        {
            return (String)GetValue(Second_manipulatedProperty);
        }
        set
        {
            Second_update_by_manipulating.Text = (Convert.ToInt32(value)<10) ? "0"+value : value;
            Debug.WriteLine(" in Second_manipulated ");
            SetValue(Second_manipulatedProperty, value);
        }
    }
    public static readonly DependencyProperty Second_manipulatedProperty =
        DependencyProperty.Register(
        "Second_manipulated",
        typeof(string),
        typeof(ClockControl),
        new PropertyMetadata(""));
    //==================================
}

所以这是我的问题:

  1. 为什么调试代码Debug.WriteLine("in Second_binded");在setter的[=更新模型 ClockTime 中的 'Second' 时,永远不会调用 ClockControl 中的 90=] 依赖项 属性。

  2. 代码Debug.WriteLine("in Second_manipulated");内setter of Second_manipulated 调用 ClockControl 中的依赖项 属性 并且代码 Value_1.Text = (Convert.ToInt32(value)<10) ? "0"+value : value; 被执行以更改 ClockControl 上的文本,但它仅在添加另一个 DispatchTimer withtin MainPage.cs 以强制代码 [=87 后才起作用=] = clock.Second.ToString(); 更新时间。为什么我必须以这种方式更新 Second_manipulated,即使我已经在 MainPage.xaml?

  3. 中将 Second_manipulated 绑定到 Second

非常欢迎任何启发我的 C# 知识的想法和评论。

谢谢

如果您想跟踪 DependencyProperty 中的更改,您必须注册一个 PropertyChangedCallback 处理程序。 属性 setter 绑定值更新时系统不会触发。

public static readonly DependencyProperty Second_bindedProperty =
        DependencyProperty.Register(
        "Second_binded",
        typeof(string),
        typeof(ClockControl),
        new PropertyMetadata("", PropertyChangedCallback));

private static void PropertyChangedCallback(DependencyObject dependencyObject,
             DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
    Debug.WriteLine(" in Second_binded callback");
}

之所以你的setter在第二个属性被命中是因为你自己用useControl.Second_manipulated = clock.Second.ToString();强行命中,这不是绑定的正确使用方式