[英]WPF layout suitable for display of binary data
我有一些捕獲的網絡數據(二進制)的WinForms顯示。 我正在嘗試將WPF作為一項學習練習,因為將來它應該更易於維護。
如您所見,二進制數據最常見的顯示格式是雙列布局,在左側顯示每個值的數值,在右側顯示對應於可打印ASCII字符的八位字節的字符串顯示。
我還希望能夠獨立更改每個值的顏色,以突出顯示檢測到的更改。
到目前為止,我已經嘗試過使用RichTextBox
,其中的FlowDocument
由Table
填充。 有一個TableRowGroup
和兩列,一列用於數字顯示,一列用於字符串顯示。
每次數據更改時,循環都會重新創建TableRowGroup
。 每16個字節的數據形成一個包含一個Paragraph
的新TableRow
。 TableCell
中的值分別作為Run
。 與需要着色的值相對應的Run
對象在放入“ Paragraph
之前進一步嵌套在“ Span
”中。
這可以工作,但是對於中等大小的數據,它明顯比WinForms RichTextBox
慢。 我想WPF並非真正設計為在單個FlowDocument
中具有FlowDocument
個Run
實例。
另外,有人告訴我,必須強制創建這么多TableCell
和Run
對象不是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.