0

私は RichTextBox コントロールを使用していますが、行間を除いてうまくいっています。PARAFORMAT2 で SendMessage を介して相互運用呼び出しを使用して、段落の行間を設定しています。

それはうまくいきます。それは私がする必要があることを正確に行います。問題は、RTF 文字列を保存してから戻すと、行間情報が失われることです。

2 つ目の RichText Box を追加し、以下のコードを使用することで、これを証明できます。richTextBox1 では、rtf 文字列が適切にフォーマットされています。しかし、richTextBox2 に到達するまでには、再びシングルスペースになっています。

    private void button15_Click(object sender, EventArgs e)
    {
        string rtf = richTextBox1.Rtf;

        richTextBox2.Rtf = rtf;
    }

フォーマットを維持するための提案はありますか? /ls 設定を使用して RTF 文字列を壊すことができることはわかっていますが、それは非常に苦痛です。どこかに欠けているだけのよりクリーンなソリューションはありますか?

アップデート:

EM_STREAMIN/OUT の提案はすばらしいものですが、残念なことに同じ狂気の結果になります。STREAMIN と STREAMOUT について詳しく読んだときに、コントロールによって提供される SaveFile と LoadFile がこれら 2 つのメッセージ コマンドの単純なラッパーであることを発見したので、簡単にするために、このサンプルではこれら 2 つのコマンドを使用しています。サンプルアプリケーションを添付しています。このコードを 1 つのテキスト ボックスと 5 つのボタンを含むフォームにカット アンド ペーストできるはずです。

読み込み、保存、クリア、DoubleSpace、SingleSpace

私は MemoryStream オブジェクトを使用して、[保存] と [読み込み] のクリックの間の一時データを処理しています。テスト: (1) DoubleSpace ボタンを使用して、1 つまたは複数の段落の間隔を変更します。(2) RichText を MemoryStream に保存します。(3) リッチ テキスト コントロールをクリアします。(4) MemoryStream データをコントロールに再ロードします。

再ロードすると、ダブルスペースのフォーマットが失われることに注意してください。他のすべての書式はそのままです。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication4
{
    public partial class Form2 : Form
    {
        MemoryStream ms = new MemoryStream();
        public Form2()
        {
            InitializeComponent();

            // First, load some crap in...
            richTextBox1.Text = "The quick red fox jumped over the lazy brown dog. The quick red fox jumped over the lazy brown dog. The quick red fox jumped over the lazy brown dog. The quick red fox jumped over the lazy brown dog. \r\nThe quick red fox jumped over the lazy brown dog. The quick red fox jumped over the lazy brown dog. The quick red fox jumped over the lazy brown dog. \r\nThe quick red fox jumped over the lazy brown dog. The quick red fox jumped over the lazy brown dog. The quick red fox jumped over the lazy brown dog. ";
        }

        private void btnLoad_Click(object sender, EventArgs e)
        {
            ms.Seek(0, SeekOrigin.Begin);
            richTextBox1.LoadFile(ms, RichTextBoxStreamType.RichText);
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            if (ms.Length > 0) ms.Dispose();

            ms = new MemoryStream();
            richTextBox1.SaveFile(ms, RichTextBoxStreamType.RichText);

        }

        private void btnSingleSpace_Click(object sender, EventArgs e)
        {
            SetParagraphSpacing(richTextBox1, 0);
        }

        private void btnDoubleSpace_Click(object sender, EventArgs e)
        {
            SetParagraphSpacing(richTextBox1, 2);
        }

        private void btnClear_Click(object sender, EventArgs e)
        {
            richTextBox1.Text = "";
        }

        [DllImport("USER32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, uint msg, IntPtr wp, IntPtr lp);

        public void SetParagraphSpacing(RichTextBox rtb, int Spacing)
        {
            PARAFORMAT2 paraform = new PARAFORMAT2();
            paraform.cbSize = Marshal.SizeOf(paraform);
            paraform.bLineSpacingRule = Convert.ToByte(Spacing);
            paraform.wReserved = 0;
            paraform.dwMask = ParaMessages.PFM_LINESPACING;

            IntPtr res = IntPtr.Zero;

            IntPtr wparam = IntPtr.Zero;

            //Get the pointer to the FORMATRANGE structure in memory
            IntPtr lparam = IntPtr.Zero;
            lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(paraform));
            Marshal.StructureToPtr(paraform, lparam, false);

            //Send the rendered data for printing 
            res = SendMessage(rtb.Handle, ParaMessages.EM_SETPARAFORMAT, wparam, lparam);

            //Free the block of memory allocated
            Marshal.FreeCoTaskMem(lparam);
        }

        [StructLayout(LayoutKind.Sequential)]

        public struct PARAFORMAT2
        {
            public int cbSize;
            public uint dwMask;
            public short wNumbering;
            public short wReserved;
            public int dxStartIndent;
            public int dxRightIndent;
            public int dxOffset;
            public short wAlignment;
            public short cTabCount;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
            public int[] rgxTabs;

            // PARAFORMAT2 from here onwards.
            public int dySpaceBefore;
            public int dySpaceAfter;
            public int dyLineSpacing;
            public short sStyle;
            public byte bLineSpacingRule;
            public byte bOutlineLevel;
            public short wShadingWeight;
            public short wNumberingStart;
            public short wNumberingStyle;
            public short wNumberingTab;
            public short wBorderSpace;
            public short wBorderWidth;
            public short wBorders;
        }

        public class ParaMessages
        {
            public static uint PFM_SPACEAFTER = 128;
            public static uint PFM_LINESPACING = 256;

            // Constants from the Platform SDK.
            public static uint EM_SETEVENTMASK = 1073;
            public static uint EM_GETPARAFORMAT = 1085;
            public static uint EM_SETPARAFORMAT = 1095;
            public static uint EM_SETTYPOGRAPHYOPTIONS = 1226;
            public static uint WM_SETREDRAW = 11;
            public static uint TO_ADVANCEDTYPOGRAPHY = 1;
            public static uint PFM_ALIGNMENT = 8;
            public static uint SCF_SELECTION = 1;
        }
    }
}
4

2 に答える 2

0

これが私が見つけたものです...私のSetParagraphSpacingは私が必要とするすべてを設定していませんでした。RichTextBoxを正しく表示するには十分でしたが、いくつかのフラグが設定されていなかったと思います。代わりに、次のように変更しましたが、現在は完全に機能しているようです。

bLineSpacingRuleと組み合わせてdyLineSpacingを使用する必要があります。bLineSpacingルールは人生のディスプレイ側のようですが、dyLineSpacingは保存/ロード中に使用されるフラグです。これらのいずれかを省略した場合、正しく保存/ロードされないか、正しく表示されません。このすべての背後にあるメカニズムはわかりませんが(誰かが説明できれば、私は感謝します)、今のところ、これは私が行った変更です。

public void SetParagraphSpacing(RichTextBox rtb, int Spacing)
{
    PARAFORMAT2 paraform = new PARAFORMAT2();
    paraform.cbSize = Marshal.SizeOf(paraform);

    // NOTE: You need both of these!
    paraform.bLineSpacingRule = Convert.ToByte(Spacing);
    paraform.dyLineSpacing = Spacing;

    paraform.wReserved = 0;
    paraform.dwMask = ParaMessages.PFM_LINESPACING;

    IntPtr res = IntPtr.Zero;

    IntPtr wparam = IntPtr.Zero;

    //Get the pointer to the FORMATRANGE structure in memory
    IntPtr lparam = IntPtr.Zero;
    lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(paraform));
    Marshal.StructureToPtr(paraform, lparam, false);

    //Send the rendered data for printing 
    res = SendMessage(rtb.Handle, ParaMessages.EM_SETPARAFORMAT, wparam, lparam);

    //Free the block of memory allocated
    Marshal.FreeCoTaskMem(lparam);
}
于 2011-03-16T15:35:08.930 に答える
0

提案されたように、コードの一部を投稿する必要があるため、説明から問題が何であるかを判断するのは非常に困難です。

私の理解では、richtextbox の Rtf プロパティを使用すると、まさに必要なことを行う必要があります。デフォルトの実装では、EM_STREAMOUTおよびEM_STREAMINメッセージを使用して、コンテンツをSF_RTF形式でリッチエディットの内外にストリーミングします。また、この SO の質問のコードを使用して手動で実行してみてください: Example of using EM_STREAMOUT with c# and RichEditBox

これが役に立てば幸いです、よろしく

于 2011-03-15T02:39:26.077 に答える