【问题标题】:WPF layout suitable for display of binary data适合显示二进制数据的 WPF 布局
【发布时间】:2014-04-05 20:12:49
【问题描述】:

我有一些捕获的网络数据(二进制)的 WinForms 显示。我正在尝试将 WPF 作为学习练习,因为它应该更易于维护。

您可能已经看到,二进制数据最常见的显示格式是双列布局,左侧显示每个值的数值,右侧显示对应于可打印 ASCII 字符的八位位组字符串。

我还希望能够独立更改每个值的颜色以突出显示检测到的更改。

到目前为止,我已经尝试使用RichTextBox,其中FlowDocumentTable 填充。有一个TableRowGroup 和两列,一列用于数字显示,一列用于字符串显示。

每次数据更改时,循环都会重新创建TableRowGroup。每 16 个字节的数据形成一个新的 TableRow,其中包含一个 ParagraphTableCell 中的值每个都作为Run 进行管理。与需要着色的值对应的Run 对象在放入Paragraph 之前进一步嵌套在Span 中。

这可行,但对于中等数据大小,它明显比 WinForms RichTextBox 慢。我想 WPF 并没有真正设计为在单个 FlowDocument 中拥有 ~4000 个 Run 实例。

另外,有人告诉我,强制创建这么多 TableCellRun 对象并不是 WPF 的预期方法。但我也不太清楚如何将其映射到视图模型,如何触发新数据的属性更改以及更改的显示选项。

任何建议将不胜感激。非常希望支持复制到剪贴板。

    internal void RenderMessageDiff(GameMessage oldMsg, GameMessage newMsg)
    {
        if (newMsg == null) return;

        var tablerows = new TableRowGroup();

        if (oldMsg == null) oldMsg = newMsg;

        var aby = newMsg.payload;
        for (int offset = 0; offset < aby.Length - 1; offset += 16)
        {
            var leftCol = new Paragraph();
            var rightCol = new Paragraph();
            int blocklen = Math.Min(16, aby.Length - offset);
            switch (selectDisplayFormat.SelectedValue as string)
            {
                case "u1":
                    for (int i = 0; i < blocklen; ++i)
                    {
                        if (i > 0) leftCol.Inlines.Add(new Run(","));
                        var v = new Run(aby[offset + i].ToString());
                        if (aby[offset + i] == oldMsg.payload[offset + i])
                            leftCol.Inlines.Add(v);
                        else
                            leftCol.Inlines.Add(new Span(v) { Foreground = Brushes.Red });
                    }
                    break;

                case "u2":
                    for (int i = 0; i + 1 < blocklen; i += 2)
                    {
                        if (i > 0) leftCol.Inlines.Add(new Run(","));
                        var v = new Run(newMsg.ConvertUInt16LE(offset + i).ToString());
                        if (newMsg.ConvertUInt16LE(offset + i) == oldMsg.ConvertUInt16LE(offset + i))
                            leftCol.Inlines.Add(v);
                        else
                            leftCol.Inlines.Add(new Span(v) { Foreground = Brushes.Red });
                    }
                    break;

                case "u4":
                    for (int i = 0; i + 3 < blocklen; i += 4)
                    {
                        if (i > 0) leftCol.Inlines.Add(new Run(","));
                        var v = new Run(newMsg.ConvertUInt32LE(offset + i).ToString());
                        if (newMsg.ConvertUInt32LE(offset + i) == oldMsg.ConvertUInt32LE(offset + i))
                            leftCol.Inlines.Add(v);
                        else
                            leftCol.Inlines.Add(new Span(v) { Foreground = Brushes.Red });
                    }
                    break;
                case "x1":
                default:
                    for (int i = 0; i < blocklen; ++i)
                    {
                        if (i > 0) leftCol.Inlines.Add(new Run(" "));
                        var v = new Run(aby[offset + i].ToString("X2"));
                        if (aby[offset + i] == oldMsg.payload[offset + i])
                            leftCol.Inlines.Add(v);
                        else
                            leftCol.Inlines.Add(new Span(v) { Foreground = Brushes.Red });
                    }

                    break;
            }
            Span changeRun = null;
            for (int i = 0; i < blocklen; ++i)
            {
                char c = (char)aby[offset + i];
                if (c < 32 || c >= 127) c = '.';
                var v = new Run(c.ToString());
                if (aby[offset + i] == oldMsg.payload[offset + i])
                {
                    rightCol.Inlines.Add(v);
                    changeRun = null;
                }
                else
                {
                    if (changeRun == null)
                        rightCol.Inlines.Add(changeRun = new Span(v) { Foreground = Brushes.Red });
                    else
                        changeRun.Inlines.Add(v);
                }
            }

            tablerows.Rows.Add(new TableRow()
            {
                Cells = { new TableCell(leftCol), new TableCell(rightCol) }
            });
        }

        textMessageDiff.RowGroups.Clear();
        textMessageDiff.RowGroups.Add(tablerows);
    }

【问题讨论】:

  • 这只是为了展示?是否有任何理由需要从 UI 编辑这些值?
  • @kmacdonald:没有编辑。但是其他重要的交互是有帮助的。复制到剪贴板。选择子集进行进一步处理。正在搜索。
  • @kmacdonald:由于着色不会影响定位,有没有办法我可以在每个段落中使用单个 Run 并覆盖渲染?我应该改用Grid 还是ListView
  • 如果您真的想进入 WPF,我建议您看看如何真正利用 MVVM 方法。您的示例是使用带有 Datatemplate 的 ItemsControl 的主要候选者,该 Datatemplate 将直观地表示每一行。您的数据模板可以由单个文本块组成。通过简单地绑定到您的行集合,您可以获得一组统一的行来显示......这越来越啰嗦了。我会尽我所知写一些东西作为答案。
  • @kmacdonald:即使我的数据每行分配了多个值?我想我可以将它分解为映射到行的切片,如果这样可以使 MVVM 更好地工作。

标签: c# wpf performance grid-layout flowdocument


【解决方案1】:

好的,这是您可以在 WPF 中执行的操作的粗略版本。

    <ItemsControl ItemsSource="{Binding YourBindingRows}">
    <ItemsControl.Resources>
        <DataTemplate DataType="{x:Type Row}">
            <StackPanel Orientation="Horizontal">
                <TextBlock>Text Representation Here</TextBlock>
                <ItemsControl ItemsSource="{Binding YourBindingCells}">
                    <ItemsControl.Resources>
                        <DataTemplate DataType="{x:Type Cell}">
                            <TextBlock Text="{Binding HexValue}"></TextBlock>
                        </DataTemplate>
                    </ItemsControl.Resources>
                </ItemsControl>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.Resources>
</ItemsControl>

您可以通过使用 ValueConverters 和属性 Binding 来实现更改背景颜色。这是另一个如何实现这一目标的粗略示例:

<TextBlock Text="{Binding HexValue}"  Background="{Binding ValueChanged, Converter={StaticResource ValueChangedBackgroundConverter}}">FF</TextBlock>

这些都是粗略的例子,我认为你需要做更多的研究来了解如何真正利用 MVVM。但是,您的项目听起来很酷,我认为它在 MVVM 环境中会很好地工作。如需进一步研究,请查看:INotifiedPropertyChanged 用于绑定,IValueConverter 用于更改颜色和其他 UI 更新。

【讨论】:

    猜你喜欢
    • 2017-11-13
    • 1970-01-01
    • 2013-07-26
    • 2021-04-01
    • 2011-08-20
    • 2010-09-05
    • 1970-01-01
    • 2014-08-09
    • 2017-01-26
    相关资源
    最近更新 更多