Reputation: 20184
I have looked around at the other questions that relate to the DependencyProperty.UnsetValue in IMultiValueConverter, but I havent found an answer that relates to my problem, I think, so here goes:
The problem is Im getting "DependencyProperty.UnsetValue" whatever I try to do with the DataContext.
I have a WPF usercontrol, and in the constructor I create an object, like this:
public partial class Misc_Vehicles_GpsTrackBarContext : UserControl
{
private TimeLine TheTimeLine { get; set; }
public Misc_Vehicles_GpsTrackBarContext()
{
InitializeComponent();
DateTime start = DateTime.Now.AddDays(-1);
TheTimeLine = new TimeLine(start, DateTime.Now);
TheTimeLine.GpsLocations.Add(new GPSLocation(55.13, 13.7, start));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.14, 13.6, start.AddMinutes(3)));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.15, 13.5, start.AddHours(6)));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.16, 13.4, start.AddHours(9)));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.17, 13.3, start.AddHours(12)));
TheTimeLine.GpsLocations.Add(new GPSLocation(55.18, 13.2, start.AddHours(15)));
this.DataContext = this;
}
}
Note: I am now expecting the XAML to be able to access the TheTimeLine (like here http://www.wpf-tutorial.com/data-binding/using-the-datacontext/)
So, the "TheTimeLine" is an object that has some relevant data and the object I want to use when I in the XAML file want to "iterate through" the GPS positions:
class TimeLine
{
public DateTime TimeStart { get; set; }
public DateTime TimeEnd { get; set; }
public TimeSpan Duration
{
get
{
return TimeEnd.Subtract(TimeStart);
}
}
public ObservableCollection<GPSLocation> GpsLocations { get; set; } = new ObservableCollection<GPSLocation>();
public TimeLine(DateTime start, DateTime end)
{
if (start > end)
throw new ArgumentOutOfRangeException("The start parameter cannot be greater than the end parameter");
TimeStart = start;
TimeEnd = end;
}
}
class DriverSession
{
public DateTime TimeStart { get; set; }
public DateTime TimeEnd { get; set; }
public TimeSpan Duration
{
get
{
return TimeEnd.Subtract(TimeStart);
}
}
public DriverSession(DateTime start, DateTime end)
{
if (start > end)
throw new ArgumentOutOfRangeException("The start parameter cannot be greater than the end parameter");
TimeStart = start;
TimeEnd = end;
}
}
And, lastly, the XAML. AS can bee seen, the Binding tags under ItemsControl below use values from both TheTimeLine (TimeStart and TimeEnd) which is the same for each GPSPosition, and then uses the ReceivedTime that is in GPSLocation:
<UserControl
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"
xmlns:local="clr-namespace:tWorks.Alfa.OperatorClient.UserControls.Vehicles"
xmlns:dxlc="http://schemas.devexpress.com/winfx/2008/xaml/layoutcontrol" x:Class="tWorks.Alfa.OperatorClient.UserControls.Vehicles.Misc_Vehicles_GpsTrackBarContext"
mc:Ignorable="d"
d:DesignHeight="260" Width="764.029">
<UserControl.Resources>
<LinearGradientBrush x:Key="HourBrush" EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF3EB1EA" Offset="0" />
<GradientStop Color="#FF61BFF1" Offset="0.5" />
<GradientStop Color="#FF01A1F4" Offset="1" />
</LinearGradientBrush>
<LinearGradientBrush x:Key="MinuteBrush" EndPoint="0.999,0.51" StartPoint="0.045,0.51">
<GradientStop Color="#FFEDA25E" Offset="0" />
<GradientStop Color="#FFEDA25E" Offset="0.15" />
<GradientStop Color="#FFFA7A05" Offset="1" />
</LinearGradientBrush>
<local:MarginLengthConverter x:Key="mEventLengthConverter"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"></RowDefinition>
<RowDefinition Height="20"></RowDefinition>
</Grid.RowDefinitions>
<Rectangle Fill="AliceBlue"></Rectangle>
<Grid Grid.Row="1">
<Rectangle Margin="0" Height="2" Fill="{DynamicResource HourBrush}"/>
<!-- **** HERE IS THE ItemsControl! **** -->
<ItemsControl x:Name="GpsLocations" ItemsSource="{Binding Path=TheTimeLine.GpsLocations}">
<ItemsPanelTemplate>
<Grid x:Name="EventContainer" Height="20" Background="Gainsboro"/>
</ItemsPanelTemplate>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<!-- **** My rectangles (lines) to draw where I have GPS positions **** -->
<Rectangle StrokeThickness="0" Width="1" Fill="{DynamicResource MinuteBrush}">
<Rectangle.Margin>
<MultiBinding Converter="{StaticResource mEventLengthConverter}">
<Binding Path="TheTimeLine.TimeStart"/> <!-- when DataContext is set to "this", i expected TheTimeLine to be accessible? -->
<Binding Path="TheTimeLine.TimeEnd"/>
<Binding Path="ReceivedTime"/> <!-- ReceivedTime is inside an object called GPSLocation, that I am iterating through -->
<Binding ElementName="EventContainer" Path="ActualWidth"/>
</MultiBinding>
</Rectangle.Margin>
</Rectangle>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</Grid>
And lastly, the annoying error =)
UPDATE After I updated according to @mm8 comments, I now see this:
So, the values from the "TheTimeLine" fails...
The XAML part regarding the ItemsControl:
<!-- **** HERE IS THE ItemsControl! TheTimeLine.GpsLocations contains GPSLocation objects that has the ReceivedTime used below **** -->
<ItemsControl x:Name="GpsLocations" ItemsSource="{Binding Path=TheTimeLine.GpsLocations}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid x:Name="EventContainer" Height="20" Background="Gainsboro"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Canvas>
<!-- **** My rectangles (lines) to draw where I have GPS positions **** -->
<Rectangle StrokeThickness="0" Width="1" Fill="{DynamicResource MinuteBrush}">
<Rectangle.Margin>
<MultiBinding Converter="{StaticResource mEventLengthConverter}">
<Binding Path="TimeStart" RelativeSource="{RelativeSource AncestorType=UserControl}"/>
<Binding Path="TimeEnd" RelativeSource="{RelativeSource AncestorType=UserControl}"/>
<Binding Path="ReceivedTime"/> <!-- ReceivedTime is inside an object called GPSLocation, ObservableCollection<GPSLocation> -->
<Binding ElementName="EventContainer" Path="ActualWidth"/>
</MultiBinding>
</Rectangle.Margin>
</Rectangle>
</Canvas>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Upvotes: 0
Views: 706
Reputation: 169360
You can only bind to public properties:
public TimeLine TheTimeLine { get; set; }
Besides, the DataContext
of an element in the ItemTemplate
is a GPSLocation
object assuming you have bound the ItemsSource
property to an IEnumerable<GPSLocation>
. If you want to bind to the TheTimeLine
property of the parent UserControl
class, you could use a RelativeSource
:
<Binding Path="TheTimeLine.TimeStart" RelativeSource="{RelativeSource AncestorType=UserControl}"/>
Upvotes: 2