運行環境:Win10 x64, NetFrameWork 4.8, 做者:烏龍哈里,日期:2019-05-05
數組
最近想寫一個相似 UltraEdit 查看文件內容,以16進制顯示每字節。首先碰到的問題就是下面這個界面:
ui
在 WPF 下嘗試了很多方法,同時讀一個28k byte 的文件,利弊以下:
方法一:用 Canvas 作容器,一個字節一個 Textbox,寫入、修改、變色等操做是很方便,結果載入數據顯示的時候要停頓10多秒,並且內存佔用達到了1g 以上,一樣的文件 UltraEdit 才佔用 28m 左右。放棄;
方法二:把 TextBox 換成輕量些的 TextBlock,內存佔用達 120m左右,載入數據也比較慢,放棄;
方法三:還用 TextBox ,可是隻用顯示頁面上能擺放的數量,再也不一個字節一個,佔用才60多兆,但用鼠標滾動翻頁時,停頓感很強,不流暢。放棄;
方法三:用 一個字節一個 GlyphRun 直接在 Canvas上畫出來,內存佔用也很大,比方法二還要大,不明因此,放棄;
方法四:用 一個字節一個 FormattedText 畫在 Canvas 上,直接在 Canvas 的 OnRender() 裏生成也佔用內存 80多兆。不在 OnRender() 裏須要把 FormattedText 轉化成 FrameworkElement,佔用直接上到120多兆。放棄
最後發現用 一個 RichTextBox 來載入數據又快又省,佔用內存才28m,和 UltraEdit 至關。(不用單個 TextBox 是由於改動時想標記不一樣顏色,TextBox 很難作到)。
之後把這些實驗的心得也記錄下來。
spa
StringBuilder sb = new StringBuilder(); for (int i = 0; i < CntData.Length; i++)//CntData是讀取文件的字節數組 { if (i % NumInLine == 0 && i != 0) //NumInLine=16 每行顯示16個字節 { sb.Append("\r\n"); } sb.Append(CntData[i].ToString("X2")); sb.Append(" "); } //--TextRange.Text=sb.ToString()方法比下面用 Paragraph 的要慢好多 //TextRange tr = new TextRange(rtbShow.Document.ContentStart, rtbShow.Document.ContentEnd); //tr.Text = sb.ToString(); Paragraph p = new Paragraph(); p.Inlines.Add(new Run(sb.ToString())); rtbShow.Document.Blocks.Add(p);//rtbShow RichTextBox 控件的名稱 InputMethod.SetIsInputMethodEnabled(rtbShow, false);//關掉輸入法 //把輸入改爲 overwrite 模式 PropertyInfo textEditorProperty = typeof(RichTextBox).GetProperty("TextEditor", BindingFlags.NonPublic | BindingFlags.Instance); object textEditor = textEditorProperty.GetValue(rtbShow, null); // set _OvertypeMode on the TextEditor PropertyInfo overtypeModeProperty = textEditor.GetType().GetProperty("_OvertypeMode", BindingFlags.NonPublic | BindingFlags.Instance); overtypeModeProperty.SetValue(textEditor, true, null);
//---計算當前鼠標後一個字符從文檔開始字符起算是第幾個字符 private int GetCharOffset(RichTextBox rtb) { TextPointer start = rtb.CaretPosition;//當前鼠標位置 int n = 0; TextPointerContext tpc = start.GetPointerContext(LogicalDirection.Backward); while (tpc!=TextPointerContext.None) { if (tpc == TextPointerContext.Text) n++; start = start.GetPositionAtOffset(-1, LogicalDirection.Backward);//注意是 -1 tpc = start.GetPointerContext(LogicalDirection.Backward); } return n-1;//從0起算 }
看了 MS 關於 GetPositionAtOffset() 的解釋:
參數
offset
Int32
偏移量(以符號數爲單位),使用它計算並返回位置。 若是偏移量爲負,則返回的 TextPointer 位於當前 TextPointer 以前;不然,位於它以後。
direction
LogicalDirection
LogicalDirection 值之一,它指定返回的 TextPointer 的邏輯方向。
上面那段程序中只能寫-1,要是是 1的話,永遠得不到 TextPointerContext.None 。orm