Reputation: 72
I am trying to bind to a dependency property of my user control from my user control however it doesn't seem to be working as the converter keeps throwing an unset dependency property error
The dependency property
public DateTime? DisplayedDate
{
get { return (DateTime?)base.GetValue(DisplayedDateProperty); }
set { base.SetValue(DisplayedDateProperty, value); }
}
public static readonly DependencyProperty DisplayedDateProperty =
DependencyProperty.Register("DisplayedDate", typeof(DateTime?), typeof(SideBarUser), new FrameworkPropertyMetadata()
{
BindsTwoWayByDefault = true,
DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
});
The XAML Binding
<UserControl.Resources>
<sys:Int32 x:Key="Test">1</sys:Int32>
<Converters:DateCountConverter x:Key="DateCountConverter"/>
</UserControl.Resources>
<TextBlock DataContext="{Binding RelativeSource={RelativeSource Self}}"
TextAlignment="Center">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource DateCountConverter}">
<Binding Path="DisplayedDate" />
<Binding Source="{StaticResource Test}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
And finally the part it's failing at in the coverter
DateTime date = (DateTime)values[0];
All together yields
System.InvalidCastException
Specified cast is not valid.
at System.Windows.Data.MultiBindingExpression.TransferValue()
at System.Windows.Data.MultiBindingExpression.Transfer()
at System.Windows.Data.MultiBindingExpression.UpdateTarget(Boolean includeInnerBindings)
at System.Windows.Data.MultiBindingExpression.AttachToContext(Boolean lastChance)
at System.Windows.Data.MultiBindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Task.Run(Boolean lastChance)
at MS.Internal.Data.DataBindEngine.Run(Object arg)
at MS.Internal.Data.DataBindEngine.OnLayoutUpdated(Object sender, EventArgs e)
at System.Windows.ContextLayoutManager.fireLayoutUpdateEvent()
at System.Windows.ContextLayoutManager.UpdateLayout()
at System.Windows.UIElement.UpdateLayout()
at System.Windows.Interop.HwndSource.SetLayoutSize()
at System.Windows.Interop.HwndSource.set_RootVisualInternal(Visual value)
at System.Windows.Interop.HwndSource.set_RootVisual(Visual value)
at MS.Internal.DeferredHwndSource.ProcessQueue(Object sender, EventArgs e)
I cannot seem to get this to work for the life of me. Am I missing something? When debugging with another instance of Visual Studio it comes up that it is an Unset Dependency property
Edit: When I comment out everything and just have
<TextBlock Text="{Binding Path=DisplayedDate, RelativeSource={RelativeSource Self}}" />
It works just fine displaying the display date. My confusion level is too great to cope with right now
EDIT EDIT: Converter code
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DateTime? date = (DateTime?)values[0];
//ToDo move most of the logic inside AppointmentsViewModel class to handle date filtering
AppointmentsViewModel MyAppointments = new AppointmentsViewModel();
String Count;
int SelectionType = (int)values[1];
//Note To Self Make Enum
switch (SelectionType)
{
case 0:
Count = MyAppointments.Appointments.Where(x => date != null && x.Beginning.HasValue && date.HasValue
&& x.Beginning.Value.Month == date.Value.Month
&& x.Beginning.Value.Year == date.Value.Year ).Count().ToString();
break;
case 1:
Count = MyAppointments.Appointments.Where(x => date != null && x.Test.HasValue && date.HasValue
&& x.Test.Value.Month == date.Value.Month
&& x.Test.Value.Year == date.Value.Year).Count().ToString();
break;
//ETC
default:
Count = MyAppointments.Appointments.Where(x => date != null && x.End.HasValue
&& date.HasValue && x.End.Value.Month == date.Value.Month
&& x.End.Value.Year == date.Value.Year).Count().ToString();
break;
}
return Count;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
Upvotes: 1
Views: 1587
Reputation: 3369
There are several problems with your code. I had to make some assumptions here, so hopefully I'm correct.
The converter
Your converter assumes that it will get 2 values of certain types. You want to be a little careful with that. Especially the first value, which comes from a binding, might be DependencyProperty.UnsetValue
if the binding has not been set yet.
So, you probably want to check if the values are correct before you start doing the actual conversion, for example:
if (values.Length != 2 || !(values[0] is DateTime?)|| !(values[1] is int))
{
return DependencyProperty.UnsetValue;
}
You should not have your converter throw exceptions, because they are treated as uncaught run-time exceptions and will terminate your application unless you have some global exception handler (see this question).
The control
Now, I assume that your DisplayedDate
property is defined on your UserControl
. If so, then this line:
<TextBlock DataContext="{Binding RelativeSource={RelativeSource Self}}"
will set the DataContext
to this TextBlock
, so when you later go to retrieve the DisplayedDate
property, it will not be found. You can fix this in 2 ways:
1) You use the ancestor-lookup binding:
"{Binding RelativeSource={RelativeSource AncestorType=local:UserControl1}}"
Of course, replace local:UserControl1
with the namespace and name of your control.
2) You define the content of the UserControl
as a Template instead, then use {RelativeSource TemplatedParent}
, which will point to the "owner" of the template, in this case, your UserControl
:
<UserControl.Template>
<ControlTemplate>
<TextBlock DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}"
TextAlignment="Center">
<TextBlock.Text>
<MultiBinding Converter="{StaticResource DateCountConverter}">
<Binding Path="DisplayedDate" />
<Binding Source="{StaticResource Test}" />
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</ControlTemplate>
</UserControl.Template>
Just put this in your XAML instead of the <TextBlock>
...</TextBlock>
part.
Maybe there are some other issues, but testing with a simple converter this worked for me.
Upvotes: 2