WPF を初めて使用する人にとっては、物事をうまく処理しているように見えます。
とにかく、これは個人的な好みかもしれませんが、私は通常、最初に可能な限り WPF レイアウト エンジンを活用しようとします。次に、どうしても必要な場合は、何をレンダリングするかを決定する際に困難に遭遇したため、描画を始めます。そうでないもの、まだ幅があるものとないものなど。
主に XAML に固執し、多値コンバーターを利用するソリューションを提案します。私が説明する他の方法と比較して、これには長所と短所がありますが、これは最も抵抗の少ない方法でした(とにかく努力のために;))
コード
EventLengthConverter.cs:
public class EventLengthConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        TimeSpan timelineDuration = (TimeSpan)values[0];
        TimeSpan relativeTime = (TimeSpan)values[1];
        double containerWidth = (double)values[2];
        double factor = relativeTime.TotalSeconds / timelineDuration.TotalSeconds;
        double rval = factor * containerWidth;
        if (targetType == typeof(Thickness))
        {
            return new Thickness(rval, 0, 0, 0);
        }
        else
        {
            return rval;
        }
    }
    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
MainWindow.xaml:
<Window x:Class="timelines.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:timelines"
    DataContext="{Binding Source={StaticResource Locator}, Path=Main}"
    Title="MainWindow" Height="350" Width="525">
<Window.Resources>
    <local:EventLengthConverter x:Key="mEventLengthConverter"/>
</Window.Resources>
<Grid>
    <ItemsControl ItemsSource="{Binding Path=TimeLines}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <ItemsControl x:Name="TimeLine" ItemsSource="{Binding Path=Events}">
                    <ItemsControl.ItemsPanel>
                        <ItemsPanelTemplate>
                            <Grid x:Name="EventContainer" Height="20" Margin="5" Background="Gainsboro"/>
                        </ItemsPanelTemplate>
                    </ItemsControl.ItemsPanel>
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Rectangle Grid.Column="1" Fill="Green" VerticalAlignment="Stretch" HorizontalAlignment="Left">
                                <Rectangle.Margin>
                                    <MultiBinding Converter="{StaticResource mEventLengthConverter}">
                                        <Binding ElementName="TimeLine" Path="DataContext.Duration"/>
                                        <Binding Path="Start"/>
                                        <Binding ElementName="EventContainer" Path="ActualWidth"/>
                                    </MultiBinding>
                                </Rectangle.Margin>
                                <Rectangle.Width>
                                    <MultiBinding Converter="{StaticResource mEventLengthConverter}">
                                        <Binding ElementName="TimeLine" Path="DataContext.Duration"/>
                                        <Binding Path="Duration"/>
                                        <Binding ElementName="EventContainer" Path="ActualWidth"/>
                                    </MultiBinding>
                                </Rectangle.Width>
                            </Rectangle>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>
これは、それぞれ 2 つと 3 つのイベントを持つ 2 つのタイムラインがある場合に表示されるものです。

説明
ここで最終的に得られるのは、最上位の TimeLine プロパティ用に 1 つ、各タイムラインのイベント用に 1 つ、ネストされた ItemsControls です。TimeLine ItemControl の ItemsPanel を単純な Grid にオーバーライドします。これは、StackPanel ではなく、すべての四角形が (データと一致するように) 同じオリジンを使用するようにするためです。
次に、各イベントは独自の四角形を取得します。これを EventLengthConverter を使用して Margin (事実上のオフセット) と幅を計算します。複数値コンバーターに必要なすべてのもの、タイムラインの期間、イベントの開始または期間、およびコンテナーの幅を指定します。コンバーターは、これらの値のいずれかが変更されるたびに呼び出されます。理想的には、各四角形がグリッド内の列を取得し、これらすべての幅をパーセンテージに設定できますが、データの動的な性質によりその余裕が失われます。
長所と短所
イベントは、要素ツリー内の独自のオブジェクトです。イベントの表示方法を細かく制御できるようになりました。それらは単なる長方形である必要はなく、より多くの動作を持つ複雑なオブジェクトにすることができます。この方法に反対する理由については、よくわかりません。誰かがパフォーマンスについて議論するかもしれませんが、これが実際的な問題であるとは想像できません。
チップ
以前と同じように、これらのデータ テンプレートを分割できます。回答で階層をより簡単に確認できるように、それらをすべてまとめて含めました。また、コンバーターの意図をより明確にしたい場合は、「EventStartConverter」と「EventWidthConverter」のようなものを 2 つ作成し、targetType に対するチェックを捨てることができます。
編集:
MainViewModel.cs
public class MainViewModel : ViewModelBase
{
    /// <summary>
    /// Initializes a new instance of the MainViewModel class.
    /// </summary>
    public MainViewModel()
    {
        TimeLine first = new TimeLine();
        first.Duration = new TimeSpan(1, 0, 0);
        first.Events.Add(new TimeLineEvent() { Start = new TimeSpan(0, 15, 0), Duration = new TimeSpan(0, 15, 0) });
        first.Events.Add(new TimeLineEvent() { Start = new TimeSpan(0, 40, 0), Duration = new TimeSpan(0, 10, 0) });
        this.TimeLines.Add(first);
        TimeLine second = new TimeLine();
        second.Duration = new TimeSpan(1, 0, 0);
        second.Events.Add(new TimeLineEvent() { Start = new TimeSpan(0, 0, 0), Duration = new TimeSpan(0, 25, 0) });
        second.Events.Add(new TimeLineEvent() { Start = new TimeSpan(0, 30, 0), Duration = new TimeSpan(0, 15, 0) });
        second.Events.Add(new TimeLineEvent() { Start = new TimeSpan(0, 50, 0), Duration = new TimeSpan(0, 10, 0) });
        this.TimeLines.Add(second);
    }
    private ObservableCollection<TimeLine> _timeLines = new ObservableCollection<TimeLine>();
    public ObservableCollection<TimeLine> TimeLines
    {
        get
        {
            return _timeLines;
        }
        set
        {
            Set(() => TimeLines, ref _timeLines, value);
        }
    }
}
public class TimeLineEvent : ObservableObject
{
    private TimeSpan _start;
    public TimeSpan Start
    {
        get
        {
            return _start;
        }
        set
        {
            Set(() => Start, ref _start, value);
        }
    }
    private TimeSpan _duration;
    public TimeSpan Duration
    {
        get
        {
            return _duration;
        }
        set
        {
            Set(() => Duration, ref _duration, value);
        }
    }
}
public class TimeLine : ObservableObject
{
    private TimeSpan _duration;
    public TimeSpan Duration
    {
        get
        {
            return _duration;
        }
        set
        {
            Set(() => Duration, ref _duration, value);
        }
    }
    private ObservableCollection<TimeLineEvent> _events = new ObservableCollection<TimeLineEvent>();
    public ObservableCollection<TimeLineEvent> Events
    {
        get
        {
            return _events;
        }
        set
        {
            Set(() => Events, ref _events, value);
        }
    }
}