1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
| public class TimelinePanel : Panel
{
public DateTime StartTime
{
get => (DateTime)GetValue(StartTimeProperty);
set => SetValue(StartTimeProperty, value);
}
public static readonly DependencyProperty StartTimeProperty =
DependencyProperty.Register(
nameof(StartTime),
typeof(DateTime),
typeof(TimelinePanel),
new FrameworkPropertyMetadata(
DateTime.MinValue,
FrameworkPropertyMetadataOptions.AffectsArrange));
public DateTime EndTime
{
get => (DateTime)GetValue(EndTimeProperty);
set => SetValue(EndTimeProperty, value);
}
public static readonly DependencyProperty EndTimeProperty =
DependencyProperty.Register(
nameof(EndTime),
typeof(DateTime),
typeof(TimelinePanel),
new FrameworkPropertyMetadata(
DateTime.MaxValue,
FrameworkPropertyMetadataOptions.AffectsArrange));
// 第一阶段:度量
protected override Size MeasureOverride(Size availableSize)
{
double maxHeight = 0;
foreach (UIElement child in InternalChildren)
{
child.Measure(availableSize);
maxHeight = Math.Max(maxHeight, child.DesiredSize.Height);
}
return new Size(availableSize.Width, maxHeight);
}
// 第二阶段:安排
protected override Size ArrangeOverride(Size finalSize)
{
var span = (EndTime - StartTime).TotalSeconds;
if (span <= 0) return finalSize;
// 跟踪每"列"已堆叠的高度
var laneHeights = new Dictionary<int, double>();
foreach (UIElement child in InternalChildren)
{
var time = Timeline.GetTime(child);
var ratio = (time - StartTime).TotalSeconds / span;
var x = ratio * finalSize.Width;
// 简化:同一时间窗内堆叠
int lane = (int)(x / 80); // 每列宽 80 DIP
double y = laneHeights.GetValueOrDefault(lane, 0);
var rect = new Rect(x, y, Math.Min(80, child.DesiredSize.Width), child.DesiredSize.Height);
child.Arrange(rect);
laneHeights[lane] = y + child.DesiredSize.Height + 4;
}
return finalSize;
}
}
|