Search code examples
c#wpfdata-bindingbindinguser-controls

Binding is not updated as expected


I'm building a simple UserControl, DoubleDatePicker, which defines a DependencyProperty, SelectedDate :

DoubleDatePicker.xaml :

<UserControl x:Class="TestWpfDoubleDatePicker.DoubleDatePicker"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit">    
<StackPanel x:Name="LayoutRoot" Background="White">
    <toolkit:DatePicker x:Name="DateInput" SelectedDate="{Binding SelectedDate,Mode=TwoWay}" Margin="5,0,5,0" />
    <TextBlock Text="{Binding SelectedDate}" />
    <toolkit:DatePicker SelectedDate="{Binding SelectedDate,Mode=TwoWay}" Margin="5,0,5,0" />
</StackPanel>

DoubleDatePicker.xaml.cs :

using System;
using System.Windows;
using System.Windows.Controls;


namespace TestWpfDoubleDatePicker
{
    public partial class DoubleDatePicker : UserControl
    {
        public static readonly DependencyProperty SelectedDateProperty =
        DependencyProperty.Register("SelectedDate", typeof(DateTime), typeof(DoubleDatePicker), null);

        public DateTime SelectedDate
        {
            get { return (DateTime)this.GetValue(SelectedDateProperty); }
            set { this.SetValue(SelectedDateProperty, value); }
        }

        public DoubleDatePicker()
        {
            this.InitializeComponent();

            this.DataContext = this;
        }
    }
}

I'd like to be able to bind the SelectedDate property from the outside but things do not seem so simple. Here is a sample code that is trying to get the value of the property in a TextBlock :

MainWindow.xaml :

<Window x:Class="TestWpfDoubleDatePicker.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestWpfDoubleDatePicker"
    Title="MainWindow" Height="350" Width="525">
<StackPanel x:Name="LayoutRoot" Background="White">
    <local:DoubleDatePicker x:Name="ddp" SelectedDate="{Binding SelectedDate}" />
    <Button Content="Update" Click="Button_Click" />
    <TextBlock Text="{Binding SelectedDate}" />
</StackPanel>

and MainWindow.xaml.cs :

using System;
using System.Windows;

namespace TestWpfDoubleDatePicker
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public static readonly DependencyProperty SelectedDateProperty =
            DependencyProperty.Register("SelectedDate", typeof(DateTime), typeof(MainWindow), null);

        public DateTime SelectedDate
        {
            get { return (DateTime)this.GetValue(SelectedDateProperty); }
            set { this.SetValue(SelectedDateProperty, value); }
        }

        public MainWindow()
        {
            InitializeComponent();

            this.DataContext = this;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.SelectedDate = this.ddp.SelectedDate;
        }
    }
}

Inside the DoubleDatePicker itself all is working fine : the SelectedDate property is updated when changed by using any of the two DatePicker, and the TextBlock of the DoubleDatePicker is updated as expected.

But, outside, the TextBlock of the MainWindow is not updated automatically and the only way to get the SelectedDate property of the DoubleDatePicker is to get it explicitly, like it's done when clicking the Button.

What am I doing wrong ?

I'm using Visual Studio Professional 2010 with WPF 4.

Thanks in advance for you help.


Solution

  • What you are doing wrong is overwriting your DataContext inside your control with this:

    this.DataContext = this;
    

    Now your DatePicker no longer binds to your intended object, but in stead binds to your DatePicker instance. I guess this is not how you intended your DatePicker to work ;).

    So, remove that line in your DatePicker, and if you do need to bind inside the XAML of your DatePicker use ElementName or RelativeSource bindings to bind to this dependency property.

    Hope this clarifies things ;)

    I took the liberty of rewriting your bindings inside your XAML of your DatePicker using ElementName bindings:

    <UserControl x:Class="TestWpfDoubleDatePicker.DoubleDatePicker"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:toolkit="http://schemas.microsoft.com/wpf/2008/toolkit" 
    x:Name="Root">    
    <StackPanel x:Name="LayoutRoot" Background="White">
        <toolkit:DatePicker x:Name="DateInput" SelectedDate="{Binding ElementName=Root, Path=SelectedDate,Mode=TwoWay}" Margin="5,0,5,0" />
        <TextBlock Text="{Binding ElementName=Root, Path=SelectedDate}" />
        <toolkit:DatePicker SelectedDate="{Binding ElementName=Root, Path=SelectedDate,Mode=TwoWay}" Margin="5,0,5,0" />
    </StackPanel>