RichTextBox (winform) Сохранить форматирование абзаца (PARAFORMAT2) - PullRequest
0 голосов
/ 15 марта 2011

Я работаю с элементом управления RichTextBox, и он отлично работает, за исключением межстрочного интервала. Я использую вызов взаимодействия через SendMessage с PARAFORMAT2, чтобы установить межстрочный интервал для абзаца.

Это прекрасно работает. Это именно то, что мне нужно сделать. Проблема в том, что когда я сохраняю строку RTF, а затем возвращаю ее обратно, информация о межстрочном интервале исчезает.

Я могу доказать это, добавив второй RichText Box и используя приведенный ниже код. В richTextBox1 строка rtf отформатирована правильно. Но к тому времени, когда он достигает richTextBox2, он снова становится через один интервал.

</p> <pre><code> private void button15_Click(object sender, EventArgs e) { string rtf = richTextBox1.Rtf; richTextBox2.Rtf = rtf; }

Есть предложения по сохранению форматирования? Я знаю, что могу войти и изменить строку RTF с помощью параметра / ls, но это ОЧЕНЬ больно. Есть ли более чистое решение, которое я где-то упускаю?

UPDATE:

Предложения EM_STREAMIN / OUT потрясающие, но, к сожалению, приводят к тому же безумию. Как я прочитал больше о STREAMIN и STREAMOUT, я обнаружил, что SaveFile и LoadFile, предоставляемые элементом управления, являются простыми обертками для этих двух команд сообщений, поэтому для простоты я использую эти две команды в этом примере. Я прилагаю пример приложения. Вы должны быть в состоянии вырезать и вставить этот код в форму с одним текстовым полем и пятью кнопками:

Загрузка, сохранение, очистка, DoubleSpace и SingleSpace

Я использую объект MemoryStream для обработки временных данных между щелчками Сохранить и Загрузить. Тест: (1) Используйте кнопку DoubleSpace, чтобы изменить интервал одного или нескольких абзацев. (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;
        }
    }
}

Ответы [ 2 ]

0 голосов
/ 16 марта 2011

Вот что я нашел ... мой SetParagraphSpacing не устанавливал все, что мне нужно. Этого было достаточно, чтобы RichTextBox отображался правильно, но я думаю, что некоторые флаги не были установлены. Вместо этого я изменил его на следующее, и, похоже, сейчас оно работает ОТЛИЧНО.

Вы должны использовать dyLineSpacing В СОЕДИНЕНИИ с bLineSpacingRule. Правило 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);
}
0 голосов
/ 15 марта 2011

Как и было предложено, вам нужно опубликовать часть своего кода, поскольку из вашего описания довольно сложно сказать, в чем проблема.

Насколько я понимаю, использование свойства Rtf для richtextbox должно делать именно то, что вам нужно. Реализация по умолчанию использует сообщения EM_STREAMOUT и EM_STREAMIN для потоковой передачи содержимого в формате SF_RTF и из него. Вы также можете попытаться сделать это вручную, используя код из этого вопроса SO: Пример использования EM_STREAMOUT с c # и RichEditBox

надеюсь, это поможет, с уважением

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...