WPF:DependencyProperty.UnsetValue 在 IMultiValueConverter 中,即使我设置了 DataContext

WPF: DependencyProperty.UnsetValue in IMultiValueConverter even though I set the DataContext

我已经查看了与 IMultiValueConverter 中的 DependencyProperty.UnsetValue 相关的其他问题,但我没有找到与我的问题相关的答案,我认为,所以这里是:

问题是我得到 "DependencyProperty.UnsetValue" 无论我尝试用 DataContext 做什么。

我有一个 WPF 用户控件,在构造函数中我创建了一个对象,如下所示:

 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;
    }
}

注意:我现在希望 XAML 能够访问 TheTimeLine(就像这里 http://www.wpf-tutorial.com/data-binding/using-the-datacontext/

因此,"TheTimeLine" 是一个具有一些相关数据的对象,当我在 XAML 文件中想要 "iterate through" GPS 位置时,我想使用该对象:

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;
    }

}

最后,XAML。可以看出,下面 ItemsControl 下的 Binding 标签使用来自 TheTimeLine(TimeStart 和 TimeEnd)的值,每个 GPSPosition 都相同,然后使用 GPSLocation 中的 ReceivedTime:

<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>

最后,烦人的错误 =)

更新 根据@mm8 的评论更新后,我现在看到了这个:

因此,"TheTimeLine" 中的值失败了...

关于 ItemsControl 的 XAML 部分:

<!-- **** 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>

您只能绑定到 public 属性:

public TimeLine TheTimeLine { get; set; }

此外,假设您已将 ItemsSource 属性 绑定到 IEnumerable<GPSLocation>。如果你想绑定到父 UserControl class 的 TheTimeLine 属性,你可以使用 RelativeSource:

<Binding Path="TheTimeLine.TimeStart" RelativeSource="{RelativeSource AncestorType=UserControl}"/>