簡體   English   中英

WPF布局適合顯示二進制數據

[英]WPF layout suitable for display of binary data

我有一些捕獲的網絡數據(二進制)的WinForms顯示。 我正在嘗試將WPF作為一項學習練習,因為將來它應該更易於維護。

如您所見,二進制數據最常見的顯示格式是雙列布局,在左側顯示每個值的數值,在右側顯示對應於可打印ASCII字符的八位字節的字符串顯示。

我還希望能夠獨立更改每個值的顏色,以突出顯示檢測到的更改。

在此處輸入圖片說明

到目前為止,我已經嘗試過使用RichTextBox ,其中的FlowDocumentTable填充。 有一個TableRowGroup和兩列,一列用於數字顯示,一列用於字符串顯示。

每次數據更改時,循環都會重新創建TableRowGroup 每16個字節的數據形成一個包含一個Paragraph的新TableRow TableCell中的值分別作為Run 與需要着色的值相對應的Run對象在放入“ Paragraph之前進一步嵌套在“ Span ”中。

這可以工作,但是對於中等大小的數據,它明顯比WinForms RichTextBox慢。 我想WPF並非真正設計為在單個FlowDocument中具有FlowDocumentRun實例。

另外,有人告訴我,必須強制創建這么多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);
    }

好的,這是您可以在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更新。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM