Wpf UserControl построить Timeline

Хочу сделать UserControl который отображал бы список задач у пользователя по времени, и поддерживал DragAndDrop для внесения задач.

Примерно как-то так, только без табличного представления:

Timeline

Timeline отображает период от 00:00 до 23:59.

Только вместо Group должно быть имя пользователя.

Объект пользователя:

public class UserViewModel : Screen
    {
        private BindableCollection<Task> _userTask;
        private readonly Employee _employer;
        public UserViewModel(Employee employer)
        {
            this._employer = employer;
            UserTask = new BindableCollection<Task>();
        }

        public long Id => _employer.Id;
        public string Fullname => $"{_employer.Surname} {_employer.Name} {_employer.Patronymic}";
        public BindableCollection<Task> UserTask
        {
            get => _userTask;
            set => Set(ref _userTask, value, nameof(UserTask));
        }
    }

Объект задачи:

public class Task
{
    public long Id { get; set; }
    public TaskType TaskType { get; set; }
    public string Description { get; set; }
    public Location Location { get; set; }
    public DateTime StartDatetime { get; set; }
    public DateTime EndDatetime { get; set; }
}

На текущий момент имею следующий вид:

введите сюда описание изображения

введите сюда описание изображения

При перетаскивании на пользователя, они привязываются к нему.

Как сделать такого вида TimeLine?

Update

Добавил разметку предложенную @aeport

<!-- Отображение сотрудников v2-->
                <ScrollViewer VerticalScrollBarVisibility="Auto">
                    <ItemsControl ItemsSource="{Binding Users}">
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Grid SnapsToDevicePixels="True">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="0.2*"/>
                                        <ColumnDefinition/>
                                    </Grid.ColumnDefinitions>
                                    <Border Background="LightGray">
                                        <TextBlock Padding="10,5" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding Fullname}" TextWrapping="WrapWithOverflow"/>
                                    </Border>
                                    <Border Grid.ColumnSpan="2" BorderThickness="0,0,0,1">
                                        <Border.BorderBrush>
                                            <VisualBrush>
                                                <VisualBrush.Visual>
                                                    <Rectangle StrokeDashArray="4 4"
                                                               Stroke="Black"
                                                               StrokeThickness="1"
                                                               Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
                                                               Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}"/>
                                                </VisualBrush.Visual>
                                            </VisualBrush>
                                        </Border.BorderBrush>
                                    </Border>
                                    <ItemsControl Grid.Column="1" ItemsSource="{Binding UserTask}" 
                                          draganddrop:DragDropHelper.IsDragSource="True"
                                          draganddrop:DragDropHelper.IsDropTarget="True">
                                        <ItemsControl.ItemTemplate>
                                            <DataTemplate>
                                                <Rectangle Fill="Green" Height="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=Canvas}}" HorizontalAlignment="Left">
                                                    <Rectangle.Width>
                                                        <MultiBinding Converter="{StaticResource MultiDateTimeToWidthConverter}">
                                                            <Binding Path="StartDatetime"/>
                                                            <Binding Path="EndDatetime"/>
                                                        </MultiBinding> 
                                                    </Rectangle.Width>
                                                </Rectangle>
                                            </DataTemplate>
                                        </ItemsControl.ItemTemplate>
                                        <ItemsControl.ItemsPanel>
                                            <ItemsPanelTemplate>
                                                <Canvas Background="AliceBlue" Margin="0,0,0,1" />
                                            </ItemsPanelTemplate>
                                        </ItemsControl.ItemsPanel>
                                        <ItemsControl.ItemContainerStyle>
                                            <Style>
                                                <Setter Property="Canvas.Left" Value="{Binding StartDatetime, Converter={StaticResource StartDateTimeToCanvasLeftPositionConverter}}" />
                                                <Setter Property="Canvas.Top" Value="0" />
                                            </Style>
                                        </ItemsControl.ItemContainerStyle>
                                    </ItemsControl>
                                </Grid>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </ScrollViewer>

Расчет стартовой точки

public class StartDateTimeToCanvasLeftPositionConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            double startTime = (value != null && value != DependencyProperty.UnsetValue) ? ((DateTime) value).TimeOfDay.TotalSeconds : 0d;
            return 86400/startTime;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Расчёт ширины элемента

public class MultiDateTimeToWidthConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var startTime = (values[0] != null && values[0] != DependencyProperty.UnsetValue) ? ((DateTime) values[0]).TimeOfDay.TotalSeconds : 0d;
            var endTime = (values[1] != null && values[1] != DependencyProperty.UnsetValue) ? ((DateTime) values[1]).TimeOfDay.TotalSeconds : 0d;
            double timeDifference = endTime - startTime;
            return timeDifference <= 1d ? 1d : (object)(86400 / timeDifference);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

Выглядит вот так:

введите сюда описание изображения

Как теперь расчитать стартовую точку от DateTime и ширину элемента от 2 dateTime.


Ответы (0 шт):