2

我正在尝试像这样在 Adob​​e Premiere 中创建时间刻度: 在此处输入图像描述 但是,我必须降低到 0.01 秒的增量。

我的时间线控件如下所示: 在此处输入图像描述

更新: 我使用了@Sten Petrov 的建议并使用了VisualBrush.

但是现在我被困在如何实现Label秒数上。

我的新代码(包含控件可以更改):

<Window x:Class="WpfApplication3.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="680.839">
<Grid Background="Black">

    <ScrollViewer VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible" >
        <ScrollViewer.ContentTemplate>
            <DataTemplate>
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="30"/>
                        <RowDefinition Height="1*"/>
                    </Grid.RowDefinitions>

                    <Grid SnapsToDevicePixels="False" UseLayoutRounding="True">
                        <Grid.Background>
                            <VisualBrush TileMode="Tile" Viewport="0,0,5,30" ViewportUnits="Absolute" Viewbox="0,0,5,30" ViewboxUnits="Absolute">
                                <VisualBrush.Visual>
                                    <Line Stroke="Coral" StrokeThickness="2" X1="0" X2="0" Y1="25" Y2="30" UseLayoutRounding="True" />
                                </VisualBrush.Visual>
                            </VisualBrush>
                        </Grid.Background>
                    </Grid>

                    <Grid Margin="50,0,0,0" SnapsToDevicePixels="False" UseLayoutRounding="True">
                        <Grid.Background>
                            <VisualBrush TileMode="Tile" Viewport="0,0,50,30" ViewportUnits="Absolute" Viewbox="0,0,50,30" ViewboxUnits="Absolute">
                                <VisualBrush.Visual>
                                    <Line Stroke="Red" StrokeThickness="2" X1="0" X2="0" Y1="20" Y2="30" UseLayoutRounding="True" />
                                </VisualBrush.Visual>
                            </VisualBrush>
                        </Grid.Background>
                    </Grid>

                    <Grid SnapsToDevicePixels="False" Height="30" UseLayoutRounding="True" >
                        <Grid.Background>
                            <VisualBrush TileMode="Tile" Viewport="0,0,500,30" ViewportUnits="Absolute" Viewbox="0,0,500,30" ViewboxUnits="Absolute">
                                <VisualBrush.Visual>
                                    <Grid HorizontalAlignment="Left" Width="500" UseLayoutRounding="True">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="21*"/>
                                            <ColumnDefinition Width="25*"/>
                                            <ColumnDefinition Width="25*"/>
                                            <ColumnDefinition Width="25*"/>
                                            <ColumnDefinition Width="25*"/>
                                            <ColumnDefinition Width="25*"/>
                                            <ColumnDefinition Width="25*"/>
                                            <ColumnDefinition Width="25*"/>
                                            <ColumnDefinition Width="25*"/>
                                            <ColumnDefinition Width="20*"/>
                                            <ColumnDefinition Width="9*"/>
                                        </Grid.ColumnDefinitions>
                                        <Grid.RowDefinitions>
                                            <RowDefinition Height="15"/>
                                            <RowDefinition Height="1*"/>
                                        </Grid.RowDefinitions>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="1" Height="9" Content=".100" Foreground="White"/>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="2" Height="9" Content=".200" Foreground="White"/>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="3" Height="9" Content=".300" Foreground="White"/>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="4" Height="9" Content=".400" Foreground="White"/>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="5" Height="9" Content=".500" Foreground="White"/>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="6" Height="9" Content=".600" Foreground="White"/>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="7" Height="9" Content=".700" Foreground="White"/>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="8" Height="9" Content=".800" Foreground="White"/>
                                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="9" Height="9" Content=".900" Foreground="White"/>
                                    </Grid>
                                </VisualBrush.Visual>
                            </VisualBrush>
                        </Grid.Background>
                    </Grid>

                    <Grid SnapsToDevicePixels="False" Height="30" UseLayoutRounding="True" Margin="500,0,0,0" >
                        <Grid.Background>
                            <VisualBrush TileMode="Tile" Viewport="0,0,500,30" ViewportUnits="Absolute" Viewbox="0,0,500,30" ViewboxUnits="Absolute">
                                <VisualBrush.Visual>
                                    <Line Stroke="Blue" StrokeThickness="2" X1="0" X2="0" Y1="10" Y2="30" UseLayoutRounding="True" />
                                </VisualBrush.Visual>
                            </VisualBrush>
                        </Grid.Background>
                    </Grid>

                    <Grid SnapsToDevicePixels="False" Height="30" UseLayoutRounding="True" Margin="491,0,0,0" >
                        <Grid.RowDefinitions>
                            <RowDefinition Height="7"/>
                            <RowDefinition Height="23"/>
                        </Grid.RowDefinitions>
                        <!--Need something here-->
                        <Label Grid.Row="0" FontFamily="Tahoma" FontSize="8" Padding="0" VerticalAlignment="Bottom" Grid.Column="0" Height="9" Content="00:00" Foreground="White"/>
                    </Grid>

                </Grid>
            </DataTemplate>
        </ScrollViewer.ContentTemplate>
    </ScrollViewer>

</Grid>

/更新

我每行 0.01 秒,所以对于 10 分钟的时间线,我正在查看绘制 60000 行 + 6000 个标签。

我之前问过一个问题:10000 多个 UI 元素,绑定还是绘制?

最初我是直接在Canvas. 然后我去使用a VisualHost,因为它应该更轻。

好吧,它不够轻。

我有一个MediaElement播放视频的视频,时间轴与视频位置同步滚动。AScrollViewer包裹我的时间线,.ScrollToHorizontalOffset大约每 10 毫秒执行一次。

如果我的时间线超过 3 分钟,视频就会关闭。我认为这是因为其中VisualHost仍然包含所有框架元素,并且滚动导致它们被重新验证。

所以现在我正在尝试生成一个Image显示,我认为应该更轻。

我在这个假设上错了吗?

现在我正面临将时间线制作成Image.

我无法将整个时间线渲染为图像,因此我将其“分块”。我在Exceptions说图像尺寸太大了。

关于我的代码:这是我的主要入口点。

public void RenderHeaderPicture()
{
    const int ChunkSize = 5000;
    var bitmapFrames = new List<BitmapFrame>();

    // generates X number of DrawingVisual's based on ChunkSize
    List<DrawingVisual> visuals = generateHeaderVisualChunks(
        AppViewModel.TimelineViewModel.HeaderWidth, ChunkSize, TimelineViewModel.ViewLevel.Level1);

    for (var i = 0; i < visuals.Count; i++)
    {
        var renderTargetBitmap = new RenderTargetBitmap(ChunkSize, 30, 96, 96, PixelFormats.Pbgra32);
        renderTargetBitmap.Render(visuals[i]);

        //test to make sure image good
        saveHeaderSegmentAsPng(string.Format("headerSeg{0}.png", i), renderTargetBitmap);

        bitmapFrames.Add(BitmapFrame.Create(renderTargetBitmap));
    }

    // put the frames back together now
    var drawingVisual = new DrawingVisual();
    using (var drawingContext = drawingVisual.RenderOpen())
    {
        for (int i = 0; i < bitmapFrames.Count; i++)
        {
            drawingContext.DrawImage(bitmapFrames[i], new Rect(i * ChunkSize, 0, bitmapFrames[i].PixelWidth, 30));
        }
        drawingContext.Close();
    }

    var newBmp = new RenderTargetBitmap(AppViewModel.TimelineViewModel.HeaderWidth, 30, 96, 96, PixelFormats.Pbgra32);
    newBmp.Render(drawingVisual);

    AppViewModel.TimelineViewModel.HeaderImageSource = newBmp;
}

这是创建DrawingVisual's

private List<DrawingVisual> generateHeaderVisualChunks(int width, int chunkSize, TimelineViewModel.ViewLevel level) 
{ 
    var ret = new List<DrawingVisual>();

    var currentTime = new TimeSpan(0, 0, 0, 0, 0);
    var timeStep = new TimeSpan(0, 0, 0, 0, (int)level);
    var currentLine = 0;

    const double DistanceBetweenLines = 5;
    const int TenthOfSecondLine = 10;
    const int SecondLine = 100;

    int iterations = (width / chunkSize);
    int remainder = width % chunkSize; //not doing anything with yet

    var grayBrush = new SolidColorBrush(Color.FromRgb(192, 192, 192));
    var grayPen = new Pen(grayBrush, 2);
    var whitePen = new Pen(Brushes.Purple, 2);

    grayBrush.Freeze();
    grayPen.Freeze();
    whitePen.Freeze();

    for (int i = 0; i < iterations; i++)
    {
        var visual = new DrawingVisual();
        using (var dc = visual.RenderOpen())
        {
            double currentX = 0;

            if (i > 0)
            {
                currentLine--;
                currentTime -= timeStep;
            }

            while (currentX <= chunkSize)
            {
                if (((currentLine % SecondLine) == 0) && currentLine != 0)
                {
                    dc.DrawLine(whitePen, new Point(currentX, 30), new Point(currentX, 15));
                    FormattedText text = null;
                    double tempX = currentX;
                    switch (level)
                    {
                        case TimelineViewModel.ViewLevel.Level1:
                            text = new FormattedText(
                                    currentTime.ToString(@"hh\:mm\:ss\.fff"),
                                    CultureInfo.CurrentCulture,
                                    FlowDirection.LeftToRight,
                                    new Typeface("Tahoma"),
                                    8,
                                    grayBrush);
                            break;
                    }

                    dc.DrawText(text, new Point((tempX - 22), 0));
                }
                else if ((((currentLine % TenthOfSecondLine) == 0) && currentLine != 0)
                            && (currentLine % SecondLine) != 0)
                {
                    dc.DrawLine(grayPen, new Point(currentX, 30), new Point(currentX, 20));

                    FormattedText text = null;
                    switch (level)
                    {
                        case TimelineViewModel.ViewLevel.Level1:
                            text = new FormattedText(
                                    string.Format(".{0}", currentTime.Milliseconds),
                                    CultureInfo.CurrentCulture,
                                    FlowDirection.LeftToRight,
                                    new Typeface("Tahoma"),
                                    8,
                                    grayBrush);
                            break;
                    }

                    dc.DrawText(text, new Point((currentX - 8), 8));
                }
                else
                {
                    dc.DrawLine(grayPen, new Point(currentX, 30), new Point(currentX, 25));
                }

                currentX += DistanceBetweenLines;
                currentLine++;
                currentTime += timeStep;
            }
        }
        ret.Add(visual);
    }
    return ret;
}

保存 png 片段:

private static void saveHeaderSegmentAsPng(string fileName, RenderTargetBitmap renderTargetBitmap)
{
    var pngBitmapEncoder = new PngBitmapEncoder();

    pngBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));
    using (var fileStream = new FileStream(fileName, FileMode.Create))
    {
        pngBitmapEncoder.Save(fileStream);
        fileStream.Flush();
        fileStream.Close();
    }
}

我所有的 png 片段都在其单独的文件中正确呈现。我的时间线一直正确渲染,直到我超过 1:20 然后事情就中断了。

看: 在此处输入图像描述

这就像图像被涂抹或其他东西。有谁知道这是怎么回事?

谢谢

4

1 回答 1

3

我正在等待我的客厅将有一台水平分辨率的电视的那一天,这将需要像你这样的方法。

废弃你刚刚在这里演示的整段代码,它永远不会变得可用可维护,你只能设法从中挤出其中的一个。

然后了解VisualBrush,那里有很多教程,它可以重复你的视觉模板,不需要 PNG,当屏幕分辨率改变时它会更好地缩放(高达 40001px 宽)

对于出现在标记上方的数字,有一百万种不同的方法,其中一些可以与上面提到的视觉画笔结合使用,例如代表您的时间线单元(两个较大标记之间的空间)的用户控件。现在将其中的几个放在一个网格中(堆栈面板、画布……如您所愿)并(动态地)调整它们的偏移量和标签 - 突然之间,您可以在屏幕上用 10 个控件表示一个无限的时间线。

于 2013-03-20T23:26:05.760 回答