C# WinForms:SelectionCharOffset和FontSize

C# WinForms:SelectionCharOffset和FontSize,c#,winforms,richtextbox,C#,Winforms,Richtextbox,我想使RichTextBox的SelectionCharOffset属性取决于字体的大小(例如SelectionCharOffset=FontSize/(2.2))。但是,由于第一个表示为整数,第二个表示为浮点,所以我必须使用显式转换 我有个问题,因为我不想那样做。这将导致信息的丢失,我必须在任何需要的时候以两种方式进行转换。我还试图强制将字体大小表示为整数,但当我将其设置为11时,它总是自动更改为11.25,以此类推 有人能帮我吗?在内部,底层的MFC富编辑控件存储的是英寸的1/1440或打印

我想使
RichTextBox
SelectionCharOffset
属性取决于字体的
大小(例如
SelectionCharOffset=FontSize/(2.2)
)。但是,由于第一个表示为整数,第二个表示为浮点,所以我必须使用显式转换

我有个问题,因为我不想那样做。这将导致信息的丢失,我必须在任何需要的时候以两种方式进行转换。我还试图强制将字体大小表示为整数,但当我将其设置为11时,它总是自动更改为11.25,以此类推


有人能帮我吗?

在内部,底层的MFC富编辑控件存储的是英寸的1/1440或打印机点的1/20。然而,由于某种原因,该函数隐藏了这种精度级别,而是以像素为单位返回,而像素的精度大约要低20倍。如果twips足够精确以满足您的需要,您可以创建自己的扩展方法来获取和设置twips中的
SelectionCharOffset
,模型为:


在内部,底层的MFC富编辑控件存储in,其为1/1440英寸或打印机点的1/20。然而,由于某种原因,该函数隐藏了这种精度级别,而是以像素为单位返回,而像素的精度大约要低20倍。如果twips足够精确以满足您的需要,您可以创建自己的扩展方法来获取和设置twips中的
SelectionCharOffset
,模型为:


底层MFC控件以twips的形式存储
yOffset
,twips是1/1440英寸或打印机点的1/20。看。只需跳过对像素的转换,您就可以基于创建自己的扩展方法
SelectionCharOffsetWips
。例如,如何通过互操作为富文本框设置
CHARFORMAT2
结构,请参阅。twips是否具有足够的精度以满足您的需要?底层MFC控件以twips格式存储
yOffset
,即1/1440英寸或打印机点的1/20。看。只需跳过对像素的转换,您就可以基于创建自己的扩展方法
SelectionCharOffsetInTwips
。有关如何通过互操作为富文本框设置
CHARFORMAT2
结构的示例,请参阅。twips的精度是否足以满足您的需要?谢谢,但它并没有真正回答我的问题。我希望能够转换为SelectionCharOffset并作为回报,而不会丢失信息。因此,如果我的字体是twips,而SelectionCharOffset是整数,那就没用了。谢谢,但这并不能真正回答我的问题。我希望能够转换为SelectionCharOffset,作为回报,不会丢失信息。因此,如果我的字体是twips,而SelectionCharOffset是整数,那就没有什么帮助了。
public static class RichTextBoxNativeMethods
{
    private static CHARFORMAT2 GetCharFormat(this RichTextBox richTextBox, bool fSelection)
    {
        // Either CHARFORMAT or CHARFORMAT2 can be used as long as the cbSize is set correctly.
        // https://msdn.microsoft.com/en-us/library/windows/desktop/bb774230.aspx

        // Force handle creation
        if (!richTextBox.IsHandleCreated)
        {
            var handle = richTextBox.Handle;
        }

        var cf2 = new CHARFORMAT2();
        UnsafeNativeMethods.SendMessage(new HandleRef(richTextBox, richTextBox.Handle), RichTextBoxConstants.EM_GETCHARFORMAT, fSelection ? RichTextBoxConstants.SCF_SELECTION : RichTextBoxConstants.SCF_DEFAULT, cf2);
        return cf2;
    }

    public static void SetSelectionCharOffsetInTwips(this RichTextBox richTextBox, int offsetInTwips)
    {
        // Adapted from http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/RichTextBox.cs,7765c7694b8e433f

        // Force handle creation
        if (!richTextBox.IsHandleCreated)
        {
            var handle = richTextBox.Handle;
        }

        var cf2 = new CHARFORMAT2();

        cf2.dwMask = RichTextBoxConstants.CFM_OFFSET;
        cf2.yOffset = offsetInTwips;

        UnsafeNativeMethods.SendMessage(new HandleRef(richTextBox, richTextBox.Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf2);
    }

    public static int GetSelectionCharOffsetInTwips(this RichTextBox richTextBox)
    {
        // Adapted from http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/RichTextBox.cs,7765c7694b8e433f
        int selCharOffset = 0;

        var cf2 = richTextBox.GetCharFormat(true);
        if ((cf2.dwMask & RichTextBoxConstants.CFM_OFFSET) != 0)
        {
            selCharOffset = cf2.yOffset;
        }
        else
        {
            // The selection contains characters of different offsets,
            // so we just return the offset of the first character.
            selCharOffset = cf2.yOffset;
        }

        return selCharOffset;
    }
}

public static class NativeMethods
{
    public const int WM_USER = 0x0400;
}

[StructLayout(LayoutKind.Sequential, Pack = 4)]
public class CHARFORMAT2
{
    // http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/NativeMethods.cs,acde044a28b57a48
    // http://pinvoke.net/default.aspx/Structures/CHARFORMAT2.html
    public int cbSize = Marshal.SizeOf(typeof(CHARFORMAT2));
    public int dwMask;
    public int dwEffects;
    public int yHeight;
    public int yOffset;
    public int crTextColor;
    public byte bCharSet;
    public byte bPitchAndFamily;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string szFaceName;
    public short wWeight;
    public short sSpacing;
    public int crBackColor;
    public int lcid;
    public int dwReserved;
    public short sStyle;
    public short wKerning;
    public byte bUnderlineType;
    public byte bAnimation;
    public byte bRevAuthor;
    public byte bReserved1;
}

public static class RichTextBoxConstants
{
    // Trimmed down from
    // http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/RichTextBoxConstants.cs,31b52ac41e96a888
    /* EM_SETCHARFORMAT wparam masks */
    /* EM_SETCHARFORMAT wparam masks */
    internal const int SCF_SELECTION = 0x0001;
    internal const int SCF_WORD = 0x0002;
    internal const int SCF_DEFAULT = 0x0000;   // set the default charformat or paraformat
    internal const int SCF_ALL = 0x0004;   // not valid with SCF_SELECTION or SCF_WORD
    internal const int SCF_USEUIRULES = 0x0008;   // modifier for SCF_SELECTION; says that
                                                // the format came from a toolbar, etc. and
                                                // therefore UI formatting rules should be
                                                // used instead of strictly formatting the
                                                // selection.

    internal const int EM_SETCHARFORMAT = (NativeMethods.WM_USER + 68);
    internal const int EM_GETCHARFORMAT = (NativeMethods.WM_USER + 58);

    internal const int CFM_BACKCOLOR = 0x04000000;
    internal const int CFM_OFFSET = 0x10000000;

    /* NOTE: CFE_AUTOCOLOR and CFE_AUTOBACKCOLOR correspond to CFM_COLOR and
       CFM_BACKCOLOR, respectively, which control them */
    internal const int CFE_AUTOBACKCOLOR = CFM_BACKCOLOR;
}