Ali Jalali
Ali Jalali

Reputation: 145

How to create a bindable property in WPF?

i have a user control. I want to create a bindable property in my user control. I create a DependencyProperty as follows:

public static readonly DependencyProperty DateProperty =
    DependencyProperty.Register("Date", typeof(DateTime), typeof(DaiesContainer), 
        new UIPropertyMetadata(DateTime.Now));

    public DateTime Date
    {
        get { return (DateTime)GetValue(DateProperty); }
        set
        {
            SetValue(DateProperty, value);
        }
    }

I then use it in my XAML:

<ctrls:DaiesContainer  Date="{Binding Date, Mode=OneWay}"/>

In my ViewModel, the get method of the Date property is called. But in my user control, Date property is not set to a value.

Upvotes: 7

Views: 17625

Answers (3)

Clemens
Clemens

Reputation: 128136

Your dependency property implementation is missing a PropertyChangedCallback that gets called when the value of the property has changed. The callback is registered as a static method, which gets the current instance (on which the property has been changed) passed as its first parameter (of type DependencyObject). You have to cast that to your class type in order to access instance fields or methods, like show below.

public static readonly DependencyProperty DateProperty =
    DependencyProperty.Register("Date", typeof(DateTime), typeof(DaiesContainer),
    new PropertyMetadata(DateTime.Now, DatePropertyChanged));

public DateTime Date
{
    get { return (DateTime)GetValue(DateProperty); }
    set { SetValue(DateProperty, value); }
}

private void DatePropertyChanged(DateTime date)
{
    //...
}

private static void DatePropertyChanged(
    DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((DaiesContainer)d).DatePropertyChanged((DateTime)e.NewValue);
}

Please note also that setting a default value of the dependency property is only done once for all instances of your class. Setting a value of DateTime.Now will hence produce the same default value for all of them, namely the time at which the static DependencyProperty is registered. I guess using something more meaningful, perhaps DateTime.MinValue, would be a better choice. As MinValue is already the default value of a newly created DateTime instance, you may even omit the default value from your property metadata:

public static readonly DependencyProperty DateProperty =
    DependencyProperty.Register("Date", typeof(DateTime), typeof(DaiesContainer),
    new PropertyMetadata(DatePropertyChanged));

Upvotes: 12

kmatyaszek
kmatyaszek

Reputation: 19296

I think that you have error in XAML UserControl.

You should binding by ElementName, e.g.:

<UserControl x:Class="WPFProject.DaiesContainer"
             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"
             x:Name="daiesContainer">
    <Grid>
        <DatePicker SelectedDate="{Binding Date, ElementName=daiesContainer}" />
    </Grid>
</UserControl>

In this case you binding to Date property of DaiesContainer class.

If you use binding without ElementName:

<DatePicker SelectedDate="{Binding Date}" />

UserControl DaiesContainer will trying find property Date in DataContext of container this user control, and if it will not find this property, you will see DatePicker with empty selected value.

Upvotes: 0

Kurubaran
Kurubaran

Reputation: 8902

Make your binding Mode TwoWay

<ctrls:DaiesContainer  Date="{Binding Date, Mode=TwoWay}"/>

Upvotes: 0

Related Questions