-2

I have a simple UserControl with 3 Dependency Properties. Day, Month and Year.

public static readonly DependencyProperty DayProperty = DependencyProperty.Register("Day", typeof(int), typeof(BoardPanel), new FrameworkPropertyMetadata(0));
public int Day
{
    get { return (int)GetValue(DayProperty); }
    set { SetValue(DayProperty, value); }
}

public static readonly DependencyProperty MonthProperty = DependencyProperty.Register("Month", typeof(int), typeof(BoardPanel), new FrameworkPropertyMetadata(0));
public int Month
{
    get { return (int)GetValue(MonthProperty); }
    set { SetValue(MonthProperty, value); }
}

public static readonly DependencyProperty YearProperty = DependencyProperty.Register("Year", typeof(int), typeof(BoardPanel), new FrameworkPropertyMetadata(0));
public int Year
{
    get { return (int)GetValue(YearProperty); }
    set { SetValue(YearProperty, value); }
}

and another string Property DayOfWeek.

public string DayOfWeek
{
    get { return new DateTime(Year, Month, Day).DayOfWeek.ToString(); }
}

The Day and DayOfWeek Properties are bound to two Textboxes in XAML.

When using this UserControl and setting all values manually everything works fine.

<c:DatePanel Day="1" Month="4" Year="2022"/>

UserControl with static values

When binding these to Properties from my ViewModel however it throws an exeption and shows that Month and Year are 0.

<c:DatePanel Day="2" Month="{Binding Month}" Year="{Binding Year}"/>

System.ArgumentOutOfRangeException: "Year, Month, and Day parameters describe an un-representable DateTime."

UserControl with bound values

I'm quite new to this topic but I'd assume that the binding is not resolved yet at the time the control gets initialized or something?

How would you do this correctly?

SevenSins
  • 63
  • 5
  • 1
    change new FrameworkPropertyMetadata(0) to new FrameworkPropertyMetadata(1) for all 3 properties. Because when you set 1st others are 0 and params of new DateTime are from 1 – Leonid Malyshev Apr 04 '22 at 13:16
  • @LeonidMalyshev this fixes the exeption however it is not quite corrent. Now I'm getting the DayOfWeek of `new DateTime(1,1,2)` instead of `new DateTime(2022,4,2)` – SevenSins Apr 04 '22 at 13:23
  • And have you set all binded properties before reading dayofweek? – Leonid Malyshev Apr 04 '22 at 13:28
  • @LeonidMalyshev the `Year` and `Month` properties are bound to the corresponding properties on my ViewModel which are set. – SevenSins Apr 04 '22 at 13:36
  • @SevenSins: So what's the value of the `Month` and `Year` source properties of the view model? If they are not `0`, the your bindings don't work. How do you set the `DataContext`? – mm8 Apr 04 '22 at 13:47
  • @mm8 The value of Month is 4 and the value of Year is 2022. I made sure the bindings are working correctly by binding them to a TextBox.Text Property. They were showing the correct values. I set the DataContext of my UserControl in its constructor `this.DataContext = this;` – SevenSins Apr 04 '22 at 14:05
  • So these properties are defined in the code-behind of the view model...? Otherwise the bindings won't work then you set `this.DataContext = this`. – mm8 Apr 04 '22 at 14:07
  • You must not explicitly set the UserControl's DataContext, because it breaks the Bindings to view model properties like `Month="{Binding Month}"` where the source property is supposed to be a property of the view model, not that of the control. See the duplicate question. – Clemens Apr 04 '22 at 14:11

1 Answers1

0

Apparently your bindings don't work.

The reason is that you have explicitly set the DataContext of the UserControl to itself which effectively prevents it from inheriting the DataContext from its parent element and bind to the properties of it.

Don't do this:

this.DataContext = this;

You should also raise a property changed event for the DayOfWeek property whenever the Day, Month or Year property is set but I see no PropertyChangedCallback in your code.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • Where do I raise the property changed event? The setters of Day, Month and Year seem to never be called. The breakpoints were never reached when debugging. – SevenSins Apr 04 '22 at 14:14
  • They are not supposed to be called for dependency properties that are bound in XAML. You need to register a [dependency property callback](https://learn.microsoft.com/en-us/dotnet/desktop/wpf/properties/dependency-property-callbacks-and-validation?WT.mc_id=WD-MVP-5001077). – mm8 Apr 04 '22 at 14:16
  • 1
    @SevenSins Be aware that this is only half of the solution. You must also change the Bindings in the XAML of your UserControl. Add either RelativeSource or ElementName, otherwise the elements in the control's XAML would bind directly to the view model instead of the control's properties. This is hard to notice immediately, since the control and view model properties have identical names. – Clemens Apr 04 '22 at 14:27
  • @Clemens I've just taken a look at your response on the assosiated similar question and got my Month/Year bindings working. However the DayOfWeek property on my UserControl tries to get the values of my Day, Month and Year properties that never get assigned a value when using bindings correct? How do I get this one working? – SevenSins Apr 04 '22 at 14:34
  • @SevenSins: Have you confirmed that the `Month` and `Year` bindings of your control are set as expected? Then you also need to make sure that you check the value of the `DayOfWeek` *after* these properties have been bound. – mm8 Apr 04 '22 at 14:35
  • @SevenSins It's not possible to tell, because we can't see your code. It may make sense to write a new question. It should however be clear that a regular readonly property won't work, because a potental Binding on the property would never be triggered. You should declare it as another (probably readonly) dependency property, of which you set the value whenever Day, Month or Year change. – Clemens Apr 04 '22 at 14:38
  • @SevenSins An alternative to the internal DayOfWeek property would be a MultiBinding to the three other properties, with an appropriate multi-value converter. You would save all the PropertyChangedCallbacks. – Clemens Apr 04 '22 at 14:43