How do I bind DateTime as DepedencyProperty of a D

2019-08-30 09:16发布

问题:

I want to learn how to use Dependency Objects and Properties. I have created this class,

    public class TestDependency : DependencyObject
    {
        public static readonly DependencyProperty TestDateTimeProperty =
            DependencyProperty.Register("TestDateTime", 
            typeof(DateTime), 
            typeof(TestDependency), 
            new PropertyMetadata(DateTime.Now));

        public DateTime TestDateTime
        {
            get { return (DateTime) GetValue(TestDateTimeProperty); }
            set { SetValue(TestDateTimeProperty, value); }
        }
    }

The window class is like this

public partial class MainWindow : Window
{
    private TestDependency td;
    public MainWindow()
    {
        InitializeComponent();
        td = new TestDependency();
        td.TestDateTime = DateTime.Now;
    }
}

Now I want to use it to show a the current DateTime in the TextBlock which updates itself every second, by adding this to a grid

<Grid>
    <TextBlock Text="{Binding TestDateTime,ElementName=td}" Width="200" Height="200"/>
</Grid>

I can see the TextBlock, but there is no Date Time value in it at all. What am I doing wrong?

回答1:

First of all if you want to update the display time once a second your going to need a timer to trigger an update. A DispatchTimer works works well for that.

public class TestDependency : DependencyObject
{
    public static readonly DependencyProperty TestDateTimeProperty =
        DependencyProperty.Register("TestDateTime", typeof(DateTime), typeof(TestDependency),
        new PropertyMetadata(DateTime.Now));

    DispatcherTimer timer;

    public TestDependency()
    {
        timer = new DispatcherTimer(new TimeSpan(0,0,1), DispatcherPriority.DataBind, new EventHandler(Callback), Application.Current.Dispatcher);
        timer.Start();

    }

    public DateTime TestDateTime
    {
        get { return (DateTime)GetValue(TestDateTimeProperty); }
        set { SetValue(TestDateTimeProperty, value); }
    }

    private void Callback(object ignore, EventArgs ex)
    {
        TestDateTime = DateTime.Now;
    }

}

Next we need to modify the XAML so it binds properly to the updated dependency object.

<Window.DataContext>
    <local:TestDependency/>
</Window.DataContext>
<Grid>
    <TextBlock Text="{Binding TestDateTime}" />
</Grid>

Since we set the DataContext in XAML you can actually delete all of the code behind code in the MainWindow constructor.



回答2:

If you just want to show some values in your TextBlock, you don't need a Dependency Object here. Try something like this:

public partial class MainWindow : Window
{
    public DateTime Test
    { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        this.Test = DateTime.Now;
    }
}

<Grid>
    <TextBlock Text="{Binding Path=Test,RelativeSource={RelativeSource AncestorType=Window,Mode=FindAncestor}}"></TextBlock>
</Grid>

Here I am not showing the code which can update the value every second. I just want to clarify that this is not the right situation to use Dependency Property. Of course you can use Dependency Property to do this. But Dependency Object and Dependency Property can offer you some extension functionality such as Data Binding. But it doesn't mean that you need to use a Dependency Object or Dependency Property as the source of the Data Binding.